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