1 // RUN: %clang_cc1 -std=c++20 -verify %s
4 typedef decltype(sizeof(int)) size_t;
6 template <class E
> struct initializer_list
{
10 constexpr initializer_list(const E
*data
, size_t size
)
11 : data(data
), size(size
) {}
12 constexpr initializer_list() : data(), size() {}
14 constexpr const E
*begin() const { return data
; }
15 constexpr const E
*end() const { return data
+ size
; }
19 struct ConstexprString
{
20 constexpr ConstexprString() : ConstexprString("") {}
21 constexpr ConstexprString(const char *p
, std::size_t size
) : data(new char[size
+1]) {
22 __builtin_memcpy(data
, p
, size
);
25 constexpr ConstexprString(const char *p
) : ConstexprString(p
, __builtin_strlen(p
)) {}
26 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);
33 constexpr ConstexprString(const ConstexprString
&o
) : ConstexprString(o
.data
) {}
34 constexpr ConstexprString(ConstexprString
&&o
) : data(o
.data
) { o
.data
= nullptr; }
35 constexpr ConstexprString
&operator=(const ConstexprString
&o
) {
36 return *this = ConstexprString(o
);
38 constexpr ConstexprString
&operator=(ConstexprString
&&o
) {
44 constexpr ~ConstexprString() { delete[] data
; }
47 friend constexpr ConstexprString
operator+(const ConstexprString
&a
, const ConstexprString
&b
) {
48 return ConstexprString(a
.data
, b
.data
);
50 friend constexpr ConstexprString
&operator+=(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;
58 template<typename
... T
> constexpr void Format(ConstexprString
&out
, const char *fmt
, T
... args
);
61 template<typename T
, int (*)[__is_integral(T
) ? 1 : -1] = nullptr>
62 constexpr Arg(T value
) {
63 bool negative
= false;
69 char str
[2] = {char('0' + value
% 10), '\0'};
70 s
= ConstexprString(str
) + s
;
76 template<typename T
, int (*)[__is_class(T
) ? 1 : -1] = nullptr>
77 constexpr Arg(const T
&value
) {
78 __builtin_dump_struct(&value
, Format
, s
);
80 constexpr Arg(const char *s
) : s(s
) {}
81 constexpr Arg(const ConstexprString
*s
) : s("\"" + *s
+ "\"") {}
82 template<typename T
, int (*)[__is_integral(T
) ? 1 : -1] = nullptr>
83 constexpr Arg(const T
*p
) : s("reference to " + Arg(*p
).s
) {}
87 template<typename
... T
> constexpr void Format(ConstexprString
&out
, const char *fmt
, T
... args
) { // #Format
88 Arg formatted_args
[] = {args
...};
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
;
96 // Skip past format specifier until we hit a conversion specifier.
98 while (!__builtin_strchr("diouxXeEfFgGcsp", *fmt
)) ++fmt
;
99 // Skip the conversion specifier too. TODO: Check it's the right one.
102 out
+= ConstexprString(fmt
);
105 template<typename T
> constexpr ConstexprString
ToString(const T
&t
) { return Arg(t
).s
; }
129 puts(ToString(B
{1, 2, 3, "hello", 4, 5, 6, 7, 8, 9, 10}).data
);
132 static_assert(ToString(B
{1, 2, 3, "hello", 4, 5, 6, 7, 8, 9, 10}) == &R
"(
138 ConstexprString s = "hello
"
145 struct (unnamed) c = {
148 int && r = reference to 10
153 __builtin_dump_struct(); // expected-error {{too few arguments to function call, expected 2, have 0}}
154 __builtin_dump_struct(1); // expected-error {{too few arguments to function call, expected 2, have 1}}
155 __builtin_dump_struct(1, 2); // expected-error {{expected pointer to struct as 1st argument to '__builtin_dump_struct', found 'int'}}
156 __builtin_dump_struct(&b
, 2); // expected-error {{expected a callable expression as 2nd argument to '__builtin_dump_struct', found 'int'}}
157 __builtin_dump_struct(&b
, Format
, 0); // expected-error {{no matching function for call to 'Format'}}
158 // expected-note@-1 {{in call to printing function with arguments '(0, "%s", "B")' while dumping struct}}
159 // expected-note@#Format {{no known conversion from 'int' to 'ConstexprString &' for 1st argument}}
163 // Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow. This
164 // would previously cause a crash.
166 int v0
, v1
, v2
, v3
, v4
, v5
, v6
, v7
, v8
, v9
, v10
, v11
, v12
, v13
, v14
, v15
, v16
,
167 v17
, v18
, v19
, v20
, v21
, v22
, v23
, v24
, v25
, v26
, v27
, v28
, v29
, v30
, v31
,
168 v32
, v33
, v34
, v35
, v36
, v37
, v38
, v39
, v40
, v41
, v42
, v43
, v44
, v45
, v46
,
169 v47
, v48
, v49
, v50
, v51
, v52
, v53
, v54
, v55
, v56
, v57
, v58
, v59
, v60
, v61
,
170 v62
, v63
, v64
, v65
, v66
, v67
, v68
, v69
, v70
, v71
, v72
, v73
, v74
, v75
, v76
,
171 v77
, v78
, v79
, v80
, v81
, v82
, v83
, v84
, v85
, v86
, v87
, v88
, v89
, v90
, v91
,
172 v92
, v93
, v94
, v95
, v96
, v97
, v98
, v99
;
176 t1 v0
, v1
, v2
, v3
, v4
, v5
, v6
, v7
, v8
, v9
, v10
, v11
, v12
, v13
, v14
, v15
, v16
,
177 v17
, v18
, v19
, v20
, v21
, v22
, v23
, v24
, v25
, v26
, v27
, v28
, v29
, v30
, v31
,
178 v32
, v33
, v34
, v35
, v36
, v37
, v38
, v39
, v40
, v41
, v42
, v43
, v44
, v45
, v46
,
179 v47
, v48
, v49
, v50
, v51
, v52
, v53
, v54
, v55
, v56
, v57
, v58
, v59
, v60
, v61
,
180 v62
, v63
, v64
, v65
, v66
, v67
, v68
, v69
, v70
, v71
, v72
, v73
, v74
, v75
, v76
,
181 v77
, v78
, v79
, v80
, v81
, v82
, v83
, v84
, v85
, v86
, v87
, v88
, v89
, v90
, v91
,
182 v92
, v93
, v94
, v95
, v96
, v97
, v98
, v99
;
185 int printf(const char *, ...);
186 void f1(t2 w
) { __builtin_dump_struct(&w
, printf
); }