// RUN: %clang_cc1 -std=c++23 -x c++ %s -verify // RUN: %clang_cc1 -std=c++20 -pedantic -x c++ %s -verify=ext,expected // RUN: %clang_cc1 -std=c++23 -x c++ %s -verify -fexperimental-new-constant-interpreter // RUN: %clang_cc1 -std=c++20 -pedantic -x c++ %s -verify=ext,expected -fexperimental-new-constant-interpreter // RUN: %clang_cc1 -std=c++26 -x c++ %s -verify // RUN: %clang_cc1 -std=c++26 -x c++ %s -verify -fexperimental-new-constant-interpreter struct A{}; struct B{ explicit operator bool() { return true; } }; template void f() { [[assume(cond)]]; // ext-warning {{C++23 extension}} } template struct S { void f() { [[assume(cond)]]; // ext-warning {{C++23 extension}} } template constexpr bool g() { [[assume(cond == sizeof(T))]]; // expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}} return true; } }; bool f2(); template constexpr void f3() { [[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}} } void g(int x) { f(); f(); S{}.f(); S{}.f(); S{}.g(); S{}.g(); [[assume(f2())]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} ext-warning {{C++23 extension}} [[assume((x = 3))]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} // ext-warning {{C++23 extension}} [[assume(x++)]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} // ext-warning {{C++23 extension}} [[assume(++x)]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} // ext-warning {{C++23 extension}} [[assume([]{ return true; }())]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} // ext-warning {{C++23 extension}} [[assume(B{})]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} // ext-warning {{C++23 extension}} [[assume((1, 2))]]; // expected-warning {{has no effect}} // ext-warning {{C++23 extension}} f3(); // expected-note {{in instantiation of}} f3(); // expected-note {{in instantiation of}} [[assume]]; // expected-error {{takes one argument}} [[assume(z)]]; // expected-error {{undeclared identifier}} [[assume(A{})]]; // expected-error {{not contextually convertible to 'bool'}} [[assume(true)]] if (true) {} // expected-error {{only applies to empty statements}} [[assume(true)]] {} // expected-error {{only applies to empty statements}} [[assume(true)]] for (;false;) {} // expected-error {{only applies to empty statements}} [[assume(true)]] while (false) {} // expected-error {{only applies to empty statements}} [[assume(true)]] label:; // expected-error {{cannot be applied to a declaration}} [[assume(true)]] goto label; // expected-error {{only applies to empty statements}} // Also check variant spellings. __attribute__((__assume__(true))); // Should not issue a warning because it doesn't use the [[]] spelling. __attribute__((assume(true))) {}; // expected-error {{only applies to empty statements}} [[clang::assume(true)]] {}; // expected-error {{only applies to empty statements}} } // Check that 'x' is ODR-used here. constexpr int h(int x) { return sizeof([=] { [[assume(x)]]; }); } // ext-warning {{C++23 extension}} static_assert(h(4) == sizeof(int)); static_assert(__has_cpp_attribute(assume) == 202207L); static_assert(__has_attribute(assume)); constexpr bool i() { // ext-error {{never produces a constant expression}} [[assume(false)]]; // ext-note {{assumption evaluated to false}} expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}} return true; } constexpr bool j(bool b) { [[assume(b)]]; // expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}} return true; } static_assert(i()); // expected-error {{not an integral constant expression}} expected-note {{in call to}} static_assert(j(true)); static_assert(j(false)); // expected-error {{not an integral constant expression}} expected-note {{in call to}} static_assert(S{}.g()); static_assert(S{}.g()); // expected-error {{not an integral constant expression}} expected-note {{in call to}} template constexpr bool f4() { [[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}} return sizeof(T) == sizeof(int); } template concept C = f4(); // expected-note 3 {{in instantiation of}} // expected-note@-1 3 {{while substituting}} // expected-error@-2 2 {{resulted in a non-constant expression}} struct D { int x; }; struct E { int x; constexpr explicit operator bool() { return false; } }; struct F { int x; int y; constexpr explicit operator bool() { return false; } }; template constexpr int f5() requires C { return 1; } // expected-note {{while checking the satisfaction}} // expected-note@-1 {{while substituting template arguments}} // expected-note@-2 {{candidate template ignored}} template constexpr int f5() requires (!C) { return 2; } // expected-note 4 {{while checking the satisfaction}} // expected-note@-1 4 {{while substituting template arguments}} // expected-note@-2 {{candidate template ignored}} static_assert(f5() == 1); static_assert(f5() == 1); // expected-note 3 {{while checking constraint satisfaction}} // expected-note@-1 3 {{in instantiation of}} // expected-error@-2 {{no matching function for call}} static_assert(f5() == 2); static_assert(f5() == 1); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}} static_assert(f5() == 2); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}} // Do not validate assumptions whose evaluation would have side-effects. constexpr int foo() { int a = 0; [[assume(a++)]] [[assume(++a)]]; // expected-warning 2 {{assumption is ignored because it contains (potential) side-effects}} ext-warning 2 {{C++23 extension}} [[assume((a+=1))]]; // expected-warning {{assumption is ignored because it contains (potential) side-effects}} ext-warning {{C++23 extension}} return a; } static_assert(foo() == 0); template void f() { [[assume(val)]]; // expected-error {{expression contains unexpanded parameter pack}} } namespace gh71858 { int foo (int x, int y) { __attribute__((assume(x == 42))); __attribute__((assume(++y == 43))); // expected-warning {{assumption is ignored because it contains (potential) side-effects}} return x + y; } } // Do not crash when assumptions are unreachable. namespace gh106898 { int foo () { while(1); int a = 0, b = 1; __attribute__((assume (a < b))); } } namespace GH114787 { // FIXME: Correct the C++26 value #if __cplusplus >= 202400L constexpr int test(auto... xs) { // FIXME: Investigate why addresses of PackIndexingExprs are printed for the next // 'in call to' note. return [&]() { // expected-note {{in call to}} [[assume( xs...[I] == 2 )]]; [[assume( xs...[I + 1] == 0 // expected-note {{assumption evaluated to false}} )]]; return xs...[I]; }.template operator()<1>(); } static_assert(test(1, 2, 3, 5, 6) == 2); // expected-error {{not an integral constant expression}} \ // expected-note {{in call to}} #endif } // namespace GH114787