xref: /llvm-project/clang/test/SemaCXX/builtin-dump-struct.cpp (revision b3392c447ad7b18a652d2ed63e8ebb7741077a98)
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