Use the regular code paths for interpreting. Add new instructions: `StartSpeculation` will reset the diagnostics pointers to `nullptr`, which will keep us from reporting any diagnostics during speculation. `EndSpeculation` will undo this. The rest depends on what `Emitter` we use. For `EvalEmitter`, we have no bytecode, so we implement `speculate()` by simply visiting the first argument of `__builtin_constant_p`. If the evaluation fails, we push a `0` on the stack, otherwise a `1`. For `ByteCodeEmitter`, add another instrucion called `BCP`, that interprets all the instructions following it until the next `EndSpeculation` instruction. If any of those instructions fails, we jump to the `EndLabel`, which brings us right before the `EndSpeculation`. We then push the result on the stack.
127 lines
3.4 KiB
C++
127 lines
3.4 KiB
C++
// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s
|
|
// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s
|
|
|
|
using intptr_t = __INTPTR_TYPE__;
|
|
|
|
static_assert(__builtin_constant_p(12), "");
|
|
static_assert(__builtin_constant_p(1.0), "");
|
|
|
|
constexpr int I = 100;
|
|
static_assert(__builtin_constant_p(I), "");
|
|
static_assert(__builtin_constant_p(I + 10), "");
|
|
static_assert(__builtin_constant_p(I + 10.0), "");
|
|
static_assert(__builtin_constant_p(nullptr), "");
|
|
static_assert(__builtin_constant_p(&I), ""); // both-error {{failed due to requirement}}
|
|
static_assert(__builtin_constant_p((void)I), ""); // both-error {{failed due to requirement}}
|
|
|
|
extern int z;
|
|
constexpr int foo(int &a) {
|
|
return __builtin_constant_p(a);
|
|
}
|
|
static_assert(!foo(z));
|
|
|
|
static_assert(__builtin_constant_p(__builtin_constant_p(1)));
|
|
|
|
constexpr bool nested(int& a) {
|
|
return __builtin_constant_p(__builtin_constant_p(a));
|
|
}
|
|
static_assert(nested(z));
|
|
|
|
constexpr bool Local() {
|
|
int z = 10;
|
|
return __builtin_constant_p(z);
|
|
}
|
|
static_assert(Local());
|
|
|
|
constexpr bool Local2() {
|
|
int z = 10;
|
|
return __builtin_constant_p(&z);
|
|
}
|
|
static_assert(!Local2());
|
|
|
|
constexpr bool Parameter(int a) {
|
|
return __builtin_constant_p(a);
|
|
}
|
|
static_assert(Parameter(10));
|
|
|
|
constexpr bool InvalidLocal() {
|
|
int *z;
|
|
{
|
|
int b = 10;
|
|
z = &b;
|
|
}
|
|
return __builtin_constant_p(z);
|
|
}
|
|
static_assert(!InvalidLocal());
|
|
|
|
template<typename T> constexpr bool bcp(T t) {
|
|
return __builtin_constant_p(t);
|
|
}
|
|
|
|
constexpr intptr_t ptr_to_int(const void *p) {
|
|
return __builtin_constant_p(1) ? (intptr_t)p : (intptr_t)p; // expected-note {{cast that performs the conversions of a reinterpret_cast}}
|
|
}
|
|
|
|
/// This is from test/SemaCXX/builtin-constant-p.cpp, but it makes no sense.
|
|
/// ptr_to_int is called before bcp(), so it fails. GCC does not accept this either.
|
|
static_assert(bcp(ptr_to_int("foo"))); // expected-error {{not an integral constant expression}} \
|
|
// expected-note {{in call to}}
|
|
|
|
constexpr bool AndFold(const int &a, const int &b) {
|
|
return __builtin_constant_p(a && b);
|
|
}
|
|
|
|
static_assert(AndFold(10, 20));
|
|
static_assert(!AndFold(z, 10));
|
|
static_assert(!AndFold(10, z));
|
|
|
|
|
|
struct F {
|
|
int a;
|
|
};
|
|
|
|
constexpr F f{12};
|
|
static_assert(__builtin_constant_p(f.a));
|
|
|
|
constexpr bool Member() {
|
|
F f;
|
|
return __builtin_constant_p(f.a);
|
|
}
|
|
static_assert(!Member());
|
|
|
|
constexpr bool Discard() {
|
|
(void)__builtin_constant_p(10);
|
|
return true;
|
|
}
|
|
static_assert(Discard());
|
|
|
|
static_assert(__builtin_constant_p((int*)123));
|
|
|
|
constexpr void func() {}
|
|
static_assert(!__builtin_constant_p(func));
|
|
|
|
/// This is from SemaCXX/builtin-constant-p and GCC agrees with the bytecode interpreter.
|
|
constexpr int mutate1() {
|
|
int n = 1;
|
|
int m = __builtin_constant_p(++n);
|
|
return n * 10 + m;
|
|
}
|
|
static_assert(mutate1() == 21); // ref-error {{static assertion failed}} \
|
|
// ref-note {{evaluates to '10 == 21'}}
|
|
|
|
/// Similar for this. GCC agrees with the bytecode interpreter.
|
|
constexpr int mutate_param(bool mutate, int ¶m) {
|
|
mutate = mutate; // Mutation of internal state is OK
|
|
if (mutate)
|
|
++param;
|
|
return param;
|
|
}
|
|
constexpr int mutate6(bool mutate) {
|
|
int n = 1;
|
|
int m = __builtin_constant_p(mutate_param(mutate, n));
|
|
return n * 10 + m;
|
|
}
|
|
static_assert(mutate6(false) == 11);
|
|
static_assert(mutate6(true) == 21); // ref-error {{static assertion failed}} \
|
|
// ref-note {{evaluates to '10 == 21'}}
|