1c4f95ef8SRichard Smith // RUN: %clang_cc1 -std=c++20 -verify %s
2c4f95ef8SRichard Smith
3c4f95ef8SRichard Smith namespace std {
4c4f95ef8SRichard Smith typedef decltype(sizeof(int)) size_t;
5c4f95ef8SRichard Smith
6c4f95ef8SRichard Smith template <class E> struct initializer_list {
7c4f95ef8SRichard Smith const E *data;
8c4f95ef8SRichard Smith size_t size;
9c4f95ef8SRichard Smith
initializer_liststd::initializer_list10c4f95ef8SRichard Smith constexpr initializer_list(const E *data, size_t size)
11c4f95ef8SRichard Smith : data(data), size(size) {}
initializer_liststd::initializer_list12c4f95ef8SRichard Smith constexpr initializer_list() : data(), size() {}
13c4f95ef8SRichard Smith
beginstd::initializer_list14c4f95ef8SRichard Smith constexpr const E *begin() const { return data; }
endstd::initializer_list15c4f95ef8SRichard Smith constexpr const E *end() const { return data + size; }
16c4f95ef8SRichard Smith };
17c4f95ef8SRichard Smith }
18c4f95ef8SRichard Smith
19c4f95ef8SRichard Smith struct ConstexprString {
ConstexprStringConstexprString20c4f95ef8SRichard Smith constexpr ConstexprString() : ConstexprString("") {}
ConstexprStringConstexprString21c4f95ef8SRichard Smith constexpr ConstexprString(const char *p, std::size_t size) : data(new char[size+1]) {
22c4f95ef8SRichard Smith __builtin_memcpy(data, p, size);
23c4f95ef8SRichard Smith data[size] = '\0';
24c4f95ef8SRichard Smith }
ConstexprStringConstexprString25c4f95ef8SRichard Smith constexpr ConstexprString(const char *p) : ConstexprString(p, __builtin_strlen(p)) {}
ConstexprStringConstexprString26c4f95ef8SRichard Smith constexpr explicit ConstexprString(const char *p, const char *q) : data(nullptr) {
27c4f95ef8SRichard Smith auto p_size = __builtin_strlen(p);
28c4f95ef8SRichard Smith auto q_size = __builtin_strlen(q);
29c4f95ef8SRichard Smith data = new char[p_size + q_size + 1];
30c4f95ef8SRichard Smith __builtin_memcpy(data, p, p_size);
31c4f95ef8SRichard Smith __builtin_memcpy(data + p_size, q, q_size + 1);
32c4f95ef8SRichard Smith }
ConstexprStringConstexprString33c4f95ef8SRichard Smith constexpr ConstexprString(const ConstexprString &o) : ConstexprString(o.data) {}
ConstexprStringConstexprString34c4f95ef8SRichard Smith constexpr ConstexprString(ConstexprString &&o) : data(o.data) { o.data = nullptr; }
operator =ConstexprString35c4f95ef8SRichard Smith constexpr ConstexprString &operator=(const ConstexprString &o) {
36c4f95ef8SRichard Smith return *this = ConstexprString(o);
37c4f95ef8SRichard Smith }
operator =ConstexprString38c4f95ef8SRichard Smith constexpr ConstexprString &operator=(ConstexprString &&o) {
39c4f95ef8SRichard Smith delete[] data;
40c4f95ef8SRichard Smith data = o.data;
41c4f95ef8SRichard Smith o.data = nullptr;
42c4f95ef8SRichard Smith return *this;
43c4f95ef8SRichard Smith }
~ConstexprStringConstexprString44c4f95ef8SRichard Smith constexpr ~ConstexprString() { delete[] data; }
45c4f95ef8SRichard Smith char *data;
46c4f95ef8SRichard Smith
operator +(const ConstexprString & a,const ConstexprString & b)47c4f95ef8SRichard Smith friend constexpr ConstexprString operator+(const ConstexprString &a, const ConstexprString &b) {
48c4f95ef8SRichard Smith return ConstexprString(a.data, b.data);
49c4f95ef8SRichard Smith }
operator +=(ConstexprString & a,const ConstexprString & b)50c4f95ef8SRichard Smith friend constexpr ConstexprString &operator+=(ConstexprString &a, const ConstexprString &b) {
51c4f95ef8SRichard Smith return a = a + b;
52c4f95ef8SRichard Smith }
operator ==(const ConstexprString & a,const ConstexprString & b)53c4f95ef8SRichard Smith friend constexpr bool operator==(const ConstexprString &a, const ConstexprString &b) {
54c4f95ef8SRichard Smith return __builtin_strcmp(a.data, b.data) == 0;
55c4f95ef8SRichard Smith }
56c4f95ef8SRichard Smith };
57c4f95ef8SRichard Smith
58c4f95ef8SRichard Smith template<typename... T> constexpr void Format(ConstexprString &out, const char *fmt, T... args);
59c4f95ef8SRichard Smith
60c4f95ef8SRichard Smith struct Arg {
61c4f95ef8SRichard Smith template<typename T, int (*)[__is_integral(T) ? 1 : -1] = nullptr>
ArgArg62c4f95ef8SRichard Smith constexpr Arg(T value) {
63c4f95ef8SRichard Smith bool negative = false;
64c4f95ef8SRichard Smith if (value < 0) {
65c4f95ef8SRichard Smith value = -value;
66c4f95ef8SRichard Smith negative = true;
67c4f95ef8SRichard Smith }
68c4f95ef8SRichard Smith while (value > 0) {
69c4f95ef8SRichard Smith char str[2] = {char('0' + value % 10), '\0'};
70c4f95ef8SRichard Smith s = ConstexprString(str) + s;
71c4f95ef8SRichard Smith value /= 10;
72c4f95ef8SRichard Smith }
73c4f95ef8SRichard Smith if (negative)
74c4f95ef8SRichard Smith s = "-" + s;
75c4f95ef8SRichard Smith }
76c4f95ef8SRichard Smith template<typename T, int (*)[__is_class(T) ? 1 : -1] = nullptr>
ArgArg77c4f95ef8SRichard Smith constexpr Arg(const T &value) {
78c4f95ef8SRichard Smith __builtin_dump_struct(&value, Format, s);
79c4f95ef8SRichard Smith }
ArgArg80c4f95ef8SRichard Smith constexpr Arg(const char *s) : s(s) {}
ArgArg81c4f95ef8SRichard Smith constexpr Arg(const ConstexprString *s) : s("\"" + *s + "\"") {}
82c4f95ef8SRichard Smith template<typename T, int (*)[__is_integral(T) ? 1 : -1] = nullptr>
ArgArg83c4f95ef8SRichard Smith constexpr Arg(const T *p) : s("reference to " + Arg(*p).s) {}
84c4f95ef8SRichard Smith ConstexprString s;
85c4f95ef8SRichard Smith };
86c4f95ef8SRichard Smith
Format(ConstexprString & out,const char * fmt,T...args)87c4f95ef8SRichard Smith template<typename... T> constexpr void Format(ConstexprString &out, const char *fmt, T... args) { // #Format
88c4f95ef8SRichard Smith Arg formatted_args[] = {args...};
89c4f95ef8SRichard Smith int i = 0;
90c4f95ef8SRichard Smith while (const char *percent = __builtin_strchr(fmt, '%')) {
91c4f95ef8SRichard Smith if (percent[1] == '%') continue;
92c4f95ef8SRichard Smith if (percent != fmt && percent[-1] == '*') --percent;
93c4f95ef8SRichard Smith out += ConstexprString(fmt, percent - fmt);
94c4f95ef8SRichard Smith out += formatted_args[i++].s;
95c4f95ef8SRichard Smith
96c4f95ef8SRichard Smith // Skip past format specifier until we hit a conversion specifier.
97c4f95ef8SRichard Smith fmt = percent;
98c4f95ef8SRichard Smith while (!__builtin_strchr("diouxXeEfFgGcsp", *fmt)) ++fmt;
99c4f95ef8SRichard Smith // Skip the conversion specifier too. TODO: Check it's the right one.
100c4f95ef8SRichard Smith ++fmt;
101c4f95ef8SRichard Smith }
102c4f95ef8SRichard Smith out += ConstexprString(fmt);
103c4f95ef8SRichard Smith }
104c4f95ef8SRichard Smith
ToString(const T & t)105c4f95ef8SRichard Smith template<typename T> constexpr ConstexprString ToString(const T &t) { return Arg(t).s; }
106c4f95ef8SRichard Smith
107c4f95ef8SRichard Smith struct A {
108c4f95ef8SRichard Smith int x, y, z : 3;
109c4f95ef8SRichard Smith int : 4;
110c4f95ef8SRichard Smith ConstexprString s;
111c4f95ef8SRichard Smith };
112c4f95ef8SRichard Smith struct B : A {
113c4f95ef8SRichard Smith int p, q;
114c4f95ef8SRichard Smith struct {
115c4f95ef8SRichard Smith int anon1, anon2;
116c4f95ef8SRichard Smith };
117c4f95ef8SRichard Smith union {
118c4f95ef8SRichard Smith int anon3;
119c4f95ef8SRichard Smith };
120c4f95ef8SRichard Smith struct {
121c4f95ef8SRichard Smith int m;
122c4f95ef8SRichard Smith } c;
123c4f95ef8SRichard Smith int &&r;
124c4f95ef8SRichard Smith };
125c4f95ef8SRichard Smith
126c4f95ef8SRichard Smith #if PRINT_OUTPUT
127c4f95ef8SRichard Smith #include <stdio.h>
main()128c4f95ef8SRichard Smith int main() {
129c4f95ef8SRichard Smith puts(ToString(B{1, 2, 3, "hello", 4, 5, 6, 7, 8, 9, 10}).data);
130c4f95ef8SRichard Smith }
131c4f95ef8SRichard Smith #else
132c4f95ef8SRichard Smith static_assert(ToString(B{1, 2, 3, "hello", 4, 5, 6, 7, 8, 9, 10}) == &R"(
133c4f95ef8SRichard Smith B {
134c4f95ef8SRichard Smith A {
135c4f95ef8SRichard Smith int x = 1
136c4f95ef8SRichard Smith int y = 2
137c4f95ef8SRichard Smith int z : 3 = 3
138c4f95ef8SRichard Smith ConstexprString s = "hello"
139c4f95ef8SRichard Smith }
140c4f95ef8SRichard Smith int p = 4
141c4f95ef8SRichard Smith int q = 5
142c4f95ef8SRichard Smith int anon1 = 6
143c4f95ef8SRichard Smith int anon2 = 7
144c4f95ef8SRichard Smith int anon3 = 8
145c4f95ef8SRichard Smith struct (unnamed) c = {
146c4f95ef8SRichard Smith int m = 9
147c4f95ef8SRichard Smith }
148c4f95ef8SRichard Smith int && r = reference to 10
149c4f95ef8SRichard Smith }
150c4f95ef8SRichard Smith )"[1]);
151c4f95ef8SRichard Smith
152*b3392c44SYounan Zhang class Incomplete; // #incomplete-type
153*b3392c44SYounan Zhang
154*b3392c44SYounan Zhang template <class T>
155*b3392c44SYounan Zhang class Class {
156*b3392c44SYounan Zhang T value = {};
157*b3392c44SYounan Zhang };
158*b3392c44SYounan Zhang
errors(B b)159c4f95ef8SRichard Smith void errors(B b) {
160*b3392c44SYounan Zhang ConstexprString cs;
161c4f95ef8SRichard Smith __builtin_dump_struct(); // expected-error {{too few arguments to function call, expected 2, have 0}}
162c4f95ef8SRichard Smith __builtin_dump_struct(1); // expected-error {{too few arguments to function call, expected 2, have 1}}
163c4f95ef8SRichard Smith __builtin_dump_struct(1, 2); // expected-error {{expected pointer to struct as 1st argument to '__builtin_dump_struct', found 'int'}}
164c4f95ef8SRichard Smith __builtin_dump_struct(&b, 2); // expected-error {{expected a callable expression as 2nd argument to '__builtin_dump_struct', found 'int'}}
165c4f95ef8SRichard Smith __builtin_dump_struct(&b, Format, 0); // expected-error {{no matching function for call to 'Format'}}
166c4f95ef8SRichard Smith // expected-note@-1 {{in call to printing function with arguments '(0, "%s", "B")' while dumping struct}}
167c4f95ef8SRichard Smith // expected-note@#Format {{no known conversion from 'int' to 'ConstexprString &' for 1st argument}}
168*b3392c44SYounan Zhang __builtin_dump_struct((Incomplete *)nullptr, Format, cs); // expected-error {{incomplete type 'Incomplete' where a complete type is required}}
169*b3392c44SYounan Zhang // expected-note@#incomplete-type {{forward declaration of 'Incomplete'}}
170*b3392c44SYounan Zhang // Ensure the Class<int> gets instantiated; otherwise crash happens.
171*b3392c44SYounan Zhang __builtin_dump_struct((Class<int> *)nullptr, Format, cs);
172c4f95ef8SRichard Smith }
173c4f95ef8SRichard Smith #endif
174677a1da6Syrong
175677a1da6Syrong // Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow. This
176677a1da6Syrong // would previously cause a crash.
177677a1da6Syrong struct t1 {
178677a1da6Syrong int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
179677a1da6Syrong v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
180677a1da6Syrong v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
181677a1da6Syrong v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
182677a1da6Syrong v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
183677a1da6Syrong v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
184677a1da6Syrong v92, v93, v94, v95, v96, v97, v98, v99;
185677a1da6Syrong };
186677a1da6Syrong
187677a1da6Syrong struct t2 {
188677a1da6Syrong t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
189677a1da6Syrong v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
190677a1da6Syrong v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
191677a1da6Syrong v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
192677a1da6Syrong v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
193677a1da6Syrong v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
194677a1da6Syrong v92, v93, v94, v95, v96, v97, v98, v99;
195677a1da6Syrong };
196677a1da6Syrong
197677a1da6Syrong int printf(const char *, ...);
f1(t2 w)198677a1da6Syrong void f1(t2 w) { __builtin_dump_struct(&w, printf); }
199