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