1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
// 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
struct A{};
struct B{ explicit operator bool() { return true; } };
template <bool cond>
void f() {
[[assume(cond)]]; // ext-warning {{C++23 extension}}
}
template <bool cond>
struct S {
void f() {
[[assume(cond)]]; // ext-warning {{C++23 extension}}
}
template <typename T>
constexpr bool g() {
[[assume(cond == sizeof(T))]]; // expected-note {{assumption evaluated to false}} ext-warning {{C++23 extension}}
return true;
}
};
bool f2();
template <typename T>
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<true>();
f<false>();
S<true>{}.f();
S<false>{}.f();
S<true>{}.g<char>();
S<true>{}.g<int>();
[[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<A>(); // expected-note {{in instantiation of}}
f3<B>(); // 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<true>{}.g<char>());
static_assert(S<false>{}.g<A>()); // expected-error {{not an integral constant expression}} expected-note {{in call to}}
template <typename T>
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 <typename T>
concept C = f4<T>(); // 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 <typename T>
constexpr int f5() requires C<T> { return 1; } // expected-note {{while checking the satisfaction}}
// expected-note@-1 {{while substituting template arguments}}
// expected-note@-2 {{candidate template ignored}}
template <typename T>
constexpr int f5() requires (!C<T>) { 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<int>() == 1);
static_assert(f5<D>() == 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<double>() == 2);
static_assert(f5<E>() == 1); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
static_assert(f5<F>() == 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 <bool ...val>
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)));
}
}
|