llvm-project/clang/test/AST/ByteCode/codegen-constexpr-unknown.cpp
Timm Baeder aa3d6b37c7
[clang][bytecode] Attach block scope variables to the root scope (#183279)
... if we don't have a block scope available. This can happen in
`EvalEmitter` scenarios and can cause local variable blocks to be
prematurely converted to dead blocks. Attach `ScopeKind::Block` variable
to the root scope instead.
2026-02-26 14:36:06 +01:00

98 lines
2.2 KiB
C++

// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -fcxx-exceptions -o - %s | FileCheck %s --check-prefix=CHECK
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -fcxx-exceptions -o - %s -fexperimental-new-constant-interpreter -DINTERP | FileCheck %s --check-prefix=CHECK,INTERP
/// CodeGenFunction::ConstantFoldsToSimpleInteger() for the if condition
/// needs to succeed and return true.
/// When re-visiting p during that evaluation, we need to attach the local
/// variable to the topmost scope, otherwise we will pick the call scope
/// of to_address and de-allocate the local variable at the end of the
/// to_address call.
/// FIXME: This is not currently correct since we still mark p as
/// constexpr-unknown and then reject it when comparing.
extern void abort2();
constexpr const int* to_address(const int *a) {
return a;
}
void rightscope() {
const int p = 0;
if (to_address(&p) == &p)
return;
abort2();
}
// CHECK: define dso_local void @_Z10rightscopev()
// CHECK-NEXT: entry:
// CHECK-NEXT: %p = alloca i32
// CHECK-NEXT: store i32 0, ptr %p
// INTERP-NEXT: call noundef ptr @_Z10to_addressPKi(ptr noundef %p)
/// In the if expression below, the read from s.i should fail.
/// If it doesn't, and we actually read the value 0, the call to
/// func() will always occur, resuliting in a runtime failure.
struct S {
mutable int i = 0;
};
void func() {
__builtin_abort();
};
void setI(const S &s) {
s.i = 12;
}
int main() {
const S s;
setI(s);
if (s.i == 0)
func();
return 0;
}
// CHECK: define dso_local noundef i32 @main()
// CHECK: br
// CHECK: if.then
// CHECK: if.end
// CHECK: ret i32 0
/// Similarly, here we revisit the BindingDecl.
struct F { int x; };
int main2() {
const F s{99};
const auto& [r1] = s;
if (&r1 != &s.x)
__builtin_abort();
return 0;
}
// CHECK: define dso_local noundef i32 @_Z5main2v()
// CHECK: br
// CHECK: if.then
// CHECK: if.end
// CHECK: ret i32 0
/// The comparison here should work and return 0.
class X {
public:
X();
X(const X&);
X(const volatile X &);
~X();
};
extern X OuterX;
X test24() {
X x;
if (&x == &OuterX)
throw 0;
return x;
}
// CHECK: define dso_local void @_Z6test24v
// CHECK-NOT: lpad
// CHECK-NOT: eh.resume