Skip to content

Commit 05eafd9

Browse files
authored
[clang][bytecode] Explicitly mark constexpr-unknown variables as such (#135806)
Instead of trying to figure out what's constexpr-unknown later on.
1 parent a56f966 commit 05eafd9

File tree

7 files changed

+65
-20
lines changed

7 files changed

+65
-20
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4293,7 +4293,8 @@ bool Compiler<Emitter>::emitConst(const APSInt &Value, const Expr *E) {
42934293

42944294
template <class Emitter>
42954295
unsigned Compiler<Emitter>::allocateLocalPrimitive(
4296-
DeclTy &&Src, PrimType Ty, bool IsConst, const ValueDecl *ExtendingDecl) {
4296+
DeclTy &&Src, PrimType Ty, bool IsConst, const ValueDecl *ExtendingDecl,
4297+
bool IsConstexprUnknown) {
42974298
// Make sure we don't accidentally register the same decl twice.
42984299
if (const auto *VD =
42994300
dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
@@ -4307,6 +4308,7 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive(
43074308
// or isa<MaterializeTemporaryExpr>().
43084309
Descriptor *D = P.createDescriptor(Src, Ty, nullptr, Descriptor::InlineDescMD,
43094310
IsConst, isa<const Expr *>(Src));
4311+
D->IsConstexprUnknown = IsConstexprUnknown;
43104312
Scope::Local Local = this->createLocal(D);
43114313
if (auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>()))
43124314
Locals.insert({VD, Local});
@@ -4320,7 +4322,8 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive(
43204322
template <class Emitter>
43214323
std::optional<unsigned>
43224324
Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty,
4323-
const ValueDecl *ExtendingDecl) {
4325+
const ValueDecl *ExtendingDecl,
4326+
bool IsConstexprUnknown) {
43244327
// Make sure we don't accidentally register the same decl twice.
43254328
if ([[maybe_unused]] const auto *VD =
43264329
dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
@@ -4349,6 +4352,7 @@ Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty,
43494352
IsTemporary, /*IsMutable=*/false, Init);
43504353
if (!D)
43514354
return std::nullopt;
4355+
D->IsConstexprUnknown = IsConstexprUnknown;
43524356

43534357
Scope::Local Local = this->createLocal(D);
43544358
if (Key)
@@ -4460,9 +4464,10 @@ bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) {
44604464
}
44614465

44624466
template <class Emitter>
4463-
VarCreationState Compiler<Emitter>::visitDecl(const VarDecl *VD) {
4467+
VarCreationState Compiler<Emitter>::visitDecl(const VarDecl *VD,
4468+
bool IsConstexprUnknown) {
44644469

4465-
auto R = this->visitVarDecl(VD, /*Toplevel=*/true);
4470+
auto R = this->visitVarDecl(VD, /*Toplevel=*/true, IsConstexprUnknown);
44664471

44674472
if (R.notCreated())
44684473
return R;
@@ -4550,7 +4555,8 @@ bool Compiler<Emitter>::visitDeclAndReturn(const VarDecl *VD,
45504555

45514556
template <class Emitter>
45524557
VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
4553-
bool Toplevel) {
4558+
bool Toplevel,
4559+
bool IsConstexprUnknown) {
45544560
// We don't know what to do with these, so just return false.
45554561
if (VD->getType().isNull())
45564562
return false;
@@ -4620,7 +4626,8 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
46204626

46214627
if (VarT) {
46224628
unsigned Offset = this->allocateLocalPrimitive(
4623-
VD, *VarT, VD->getType().isConstQualified());
4629+
VD, *VarT, VD->getType().isConstQualified(), nullptr,
4630+
IsConstexprUnknown);
46244631
if (Init) {
46254632
// If this is a toplevel declaration, create a scope for the
46264633
// initializer.
@@ -4636,7 +4643,8 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
46364643
}
46374644
}
46384645
} else {
4639-
if (std::optional<unsigned> Offset = this->allocateLocal(VD)) {
4646+
if (std::optional<unsigned> Offset = this->allocateLocal(
4647+
VD, VD->getType(), nullptr, IsConstexprUnknown)) {
46404648
if (!Init)
46414649
return true;
46424650

@@ -6461,7 +6469,7 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
64616469

64626470
// In case we need to re-visit a declaration.
64636471
auto revisit = [&](const VarDecl *VD) -> bool {
6464-
auto VarState = this->visitDecl(VD);
6472+
auto VarState = this->visitDecl(VD, /*IsConstexprUnknown=*/true);
64656473

64666474
if (VarState.notCreated())
64676475
return true;

clang/lib/AST/ByteCode/Compiler.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,10 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
286286
/// intact.
287287
bool delegate(const Expr *E);
288288
/// Creates and initializes a variable from the given decl.
289-
VarCreationState visitVarDecl(const VarDecl *VD, bool Toplevel = false);
290-
VarCreationState visitDecl(const VarDecl *VD);
289+
VarCreationState visitVarDecl(const VarDecl *VD, bool Toplevel = false,
290+
bool IsConstexprUnknown = false);
291+
VarCreationState visitDecl(const VarDecl *VD,
292+
bool IsConstexprUnknown = false);
291293
/// Visit an APValue.
292294
bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
293295
bool visitAPValueInitializer(const APValue &Val, const Expr *E, QualType T);
@@ -303,12 +305,14 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
303305

304306
/// Creates a local primitive value.
305307
unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst,
306-
const ValueDecl *ExtendingDecl = nullptr);
308+
const ValueDecl *ExtendingDecl = nullptr,
309+
bool IsConstexprUnknown = false);
307310

308311
/// Allocates a space storing a local given its type.
309312
std::optional<unsigned>
310313
allocateLocal(DeclTy &&Decl, QualType Ty = QualType(),
311-
const ValueDecl *ExtendingDecl = nullptr);
314+
const ValueDecl *ExtendingDecl = nullptr,
315+
bool IsConstexprUnknown = false);
312316
std::optional<unsigned> allocateTemporary(const Expr *E);
313317

314318
private:

clang/lib/AST/ByteCode/Descriptor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ struct Descriptor final {
168168
const bool IsArray = false;
169169
/// Flag indicating if this is a dummy descriptor.
170170
bool IsDummy = false;
171+
bool IsConstexprUnknown = false;
171172

172173
/// Storage management methods.
173174
const BlockCtorFn CtorFn = nullptr;

clang/lib/AST/ByteCode/Disasm.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const {
376376

377377
if (isDummy())
378378
OS << " dummy";
379+
if (IsConstexprUnknown)
380+
OS << " constexpr-unknown";
379381
}
380382

381383
/// Dump descriptor, including all valid offsets.

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,15 +299,14 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
299299
TYPE_SWITCH(Ty, S.Stk.discard<T>());
300300
}
301301

302-
// FIXME: Instead of using this fairly expensive test, we should
303-
// just mark constexpr-unknown values when creating them.
304302
bool isConstexprUnknown(const Pointer &P) {
305303
if (!P.isBlockPointer())
306304
return false;
305+
307306
if (P.isDummy())
308-
return false;
309-
const VarDecl *VD = P.block()->getDescriptor()->asVarDecl();
310-
return VD && VD->hasLocalStorage() && !isa<ParmVarDecl>(VD);
307+
return isa_and_nonnull<ParmVarDecl>(P.getDeclDesc()->asValueDecl());
308+
309+
return P.getDeclDesc()->IsConstexprUnknown;
311310
}
312311

313312
bool CheckBCPResult(InterpState &S, const Pointer &Ptr) {

clang/lib/AST/ByteCode/Program.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) {
156156
if (const auto *E = dyn_cast<const Expr *>(D)) {
157157
QT = E->getType();
158158
} else {
159-
const ValueDecl *VD = cast<ValueDecl>(cast<const Decl *>(D));
159+
const auto *VD = cast<ValueDecl>(cast<const Decl *>(D));
160160
IsWeak = VD->isWeak();
161161
QT = VD->getType();
162162
if (const auto *RT = QT->getAs<ReferenceType>())

clang/test/AST/ByteCode/codegen.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s
2-
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s
1+
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s -fcxx-exceptions | FileCheck %s
2+
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s -fcxx-exceptions -fexperimental-new-constant-interpreter | FileCheck %s
33

44
#ifdef __SIZEOF_INT128__
55
// CHECK: @PR11705 = global i128 0
@@ -104,3 +104,34 @@ int notdead() {
104104
}
105105
// CHECK: _ZZ7notdeadvEN3$_0clEv
106106
// CHECK: ret i32 %cond
107+
108+
/// The conmparison of those two parameters should NOT work.
109+
bool paramcmp(const int& lhs, const int& rhs) {
110+
if (&lhs == &rhs)
111+
return true;
112+
return false;
113+
}
114+
// CHECK: _Z8paramcmpRKiS0_
115+
// CHECK: if.then
116+
// CHECK: if.end
117+
118+
/// &x == &OuterX should work and return 0.
119+
class X {
120+
public:
121+
X();
122+
X(const X&);
123+
X(const volatile X &);
124+
~X();
125+
};
126+
127+
extern X OuterX;
128+
129+
X test24() {
130+
X x;
131+
if (&x == &OuterX)
132+
throw 0;
133+
return x;
134+
}
135+
// CHECK: _Z6test24v
136+
// CHECK-NOT: eh.resume
137+
// CHECK-NOT: unreachable

0 commit comments

Comments
 (0)