xref: /llvm-project/clang/test/SemaCXX/cxx23-assume.cpp (revision 3972ed57088f6515b787d7d38dec03dc74e51827)
1 // RUN: %clang_cc1 -std=c++23  -x c++ %s -verify
2 // RUN: %clang_cc1 -std=c++20 -pedantic -x c++ %s -verify=ext,expected
3 // RUN: %clang_cc1 -std=c++23  -x c++ %s -verify -fexperimental-new-constant-interpreter
4 // RUN: %clang_cc1 -std=c++20 -pedantic -x c++ %s -verify=ext,expected -fexperimental-new-constant-interpreter
5 // RUN: %clang_cc1 -std=c++26  -x c++ %s -verify
6 // RUN: %clang_cc1 -std=c++26  -x c++ %s -verify -fexperimental-new-constant-interpreter
7 
8 struct A{};
9 struct B{ explicit operator bool() { return true; } };
10 
11 template <bool cond>
12 void f() {
13   [[assume(cond)]]; // ext-warning {{C++23 extension}}
14 }
15 
16 template <bool cond>
17 struct S {
18   void f() {
19     [[assume(cond)]]; // ext-warning {{C++23 extension}}
20   }
21 
22   template <typename T>
23   constexpr bool g() {
24     [[assume(cond == sizeof(T))]]; // expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}}
25     return true;
26   }
27 };
28 
29 bool f2();
30 
31 template <typename T>
32 constexpr void f3() {
33   [[assume(T{})]]; // expected-error {{not contextually convertible to 'bool'}} expected-warning {{assumption is ignored because it contains (potential) side-effects}} ext-warning {{C++23 extension}}
34 }
35 
36 void g(int x) {
37   f<true>();
38   f<false>();
39   S<true>{}.f();
40   S<false>{}.f();
41   S<true>{}.g<char>();
42   S<true>{}.g<int>();
43   [[assume(f2())]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} ext-warning {{C++23 extension}}
44 
45   [[assume((x = 3))]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} // ext-warning {{C++23 extension}}
46   [[assume(x++)]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} // ext-warning {{C++23 extension}}
47   [[assume(++x)]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} // ext-warning {{C++23 extension}}
48   [[assume([]{ return true; }())]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} // ext-warning {{C++23 extension}}
49   [[assume(B{})]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} // ext-warning {{C++23 extension}}
50   [[assume((1, 2))]]; // expected-warning {{has no effect}} // ext-warning {{C++23 extension}}
51 
52   f3<A>(); // expected-note {{in instantiation of}}
53   f3<B>(); // expected-note {{in instantiation of}}
54   [[assume]]; // expected-error {{takes one argument}}
55   [[assume(z)]]; // expected-error {{undeclared identifier}}
56   [[assume(A{})]]; // expected-error {{not contextually convertible to 'bool'}}
57   [[assume(true)]] if (true) {} // expected-error {{only applies to empty statements}}
58   [[assume(true)]] {} // expected-error {{only applies to empty statements}}
59   [[assume(true)]] for (;false;) {} // expected-error {{only applies to empty statements}}
60   [[assume(true)]] while (false) {} // expected-error {{only applies to empty statements}}
61   [[assume(true)]] label:; // expected-error {{cannot be applied to a declaration}}
62   [[assume(true)]] goto label; // expected-error {{only applies to empty statements}}
63 
64   // Also check variant spellings.
65   __attribute__((__assume__(true))); // Should not issue a warning because it doesn't use the [[]] spelling.
66   __attribute__((assume(true))) {}; // expected-error {{only applies to empty statements}}
67   [[clang::assume(true)]] {}; // expected-error {{only applies to empty statements}}
68 }
69 
70 // Check that 'x' is ODR-used here.
71 constexpr int h(int x) { return sizeof([=] { [[assume(x)]]; }); } // ext-warning {{C++23 extension}}
72 static_assert(h(4) == sizeof(int));
73 
74 static_assert(__has_cpp_attribute(assume) == 202207L);
75 static_assert(__has_attribute(assume));
76 
77 constexpr bool i() { // ext-error {{never produces a constant expression}}
78   [[assume(false)]]; // ext-note {{assumption evaluated to false}} expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}}
79   return true;
80 }
81 
82 constexpr bool j(bool b) {
83   [[assume(b)]]; // expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}}
84   return true;
85 }
86 
87 static_assert(i()); // expected-error {{not an integral constant expression}} expected-note {{in call to}}
88 static_assert(j(true));
89 static_assert(j(false)); // expected-error {{not an integral constant expression}} expected-note {{in call to}}
90 static_assert(S<true>{}.g<char>());
91 static_assert(S<false>{}.g<A>()); // expected-error {{not an integral constant expression}} expected-note {{in call to}}
92 
93 
94 template <typename T>
95 constexpr bool f4() {
96   [[assume(!T{})]]; // expected-error {{invalid argument type 'D'}} // expected-warning 2 {{assumption is ignored because it contains (potential) side-effects}} ext-warning {{C++23 extension}}
97   return sizeof(T) == sizeof(int);
98 }
99 
100 template <typename T>
101 concept C = f4<T>(); // expected-note 3 {{in instantiation of}}
102                      // expected-note@-1 3 {{while substituting}}
103                      // expected-error@-2 2 {{resulted in a non-constant expression}}
104 
105 struct D {
106   int x;
107 };
108 
109 struct E {
110   int x;
111   constexpr explicit operator bool() { return false; }
112 };
113 
114 struct F {
115   int x;
116   int y;
117   constexpr explicit operator bool() { return false; }
118 };
119 
120 template <typename T>
121 constexpr int f5() requires C<T> { return 1; } // expected-note {{while checking the satisfaction}}
122                                                // expected-note@-1 {{while substituting template arguments}}
123                                                // expected-note@-2 {{candidate template ignored}}
124 
125 template <typename T>
126 constexpr int f5() requires (!C<T>) { return 2; } // expected-note 4 {{while checking the satisfaction}}
127                                                   // expected-note@-1 4 {{while substituting template arguments}}
128                                                   // expected-note@-2 {{candidate template ignored}}
129 
130 static_assert(f5<int>() == 1);
131 static_assert(f5<D>() == 1); // expected-note 3 {{while checking constraint satisfaction}}
132                              // expected-note@-1 3 {{in instantiation of}}
133                              // expected-error@-2 {{no matching function for call}}
134 
135 static_assert(f5<double>() == 2);
136 static_assert(f5<E>() == 1); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
137 static_assert(f5<F>() == 2); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
138 
139 // Do not validate assumptions whose evaluation would have side-effects.
140 constexpr int foo() {
141   int a = 0;
142   [[assume(a++)]] [[assume(++a)]]; // expected-warning 2 {{assumption is ignored because it contains (potential) side-effects}} ext-warning 2 {{C++23 extension}}
143   [[assume((a+=1))]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} ext-warning {{C++23 extension}}
144   return a;
145 }
146 
147 static_assert(foo() == 0);
148 
149 template <bool ...val>
150 void f() {
151     [[assume(val)]]; // expected-error {{expression contains unexpanded parameter pack}}
152 }
153 
154 namespace gh71858 {
155 int
156 foo (int x, int y)
157 {
158   __attribute__((assume(x == 42)));
159   __attribute__((assume(++y == 43))); // expected-warning {{assumption is ignored because it contains (potential) side-effects}}
160   return x + y;
161 }
162 }
163 
164 // Do not crash when assumptions are unreachable.
165 namespace gh106898 {
166 int foo () {
167     while(1);
168     int a = 0, b = 1;
169     __attribute__((assume (a < b)));
170 }
171 }
172 
173 namespace GH114787 {
174 
175 // FIXME: Correct the C++26 value
176 #if __cplusplus >= 202400L
177 
178 constexpr int test(auto... xs) {
179   // FIXME: Investigate why addresses of PackIndexingExprs are printed for the next
180   // 'in call to' note.
181   return [&]<int I>() { // expected-note {{in call to}}
182     [[assume(
183       xs...[I] == 2
184     )]];
185     [[assume(
186       xs...[I + 1] == 0 // expected-note {{assumption evaluated to false}}
187     )]];
188     return xs...[I];
189   }.template operator()<1>();
190 }
191 
192 static_assert(test(1, 2, 3, 5, 6) == 2); // expected-error {{not an integral constant expression}} \
193                                          // expected-note {{in call to}}
194 
195 #endif
196 
197 } // namespace GH114787
198