Skip to content

Commit 2d38bec

Browse files
committed
[clang][Interp][NFC] Don't create variables in non-constant contexts
When the evaluation in a contant context fails, we would otherwise try to access and use that variable later in a (maybe) non-constant context. If the evaluation succeeds in the non-constant context, we never reported success because we reported failure from the first time we visited the variable.
1 parent e5d0627 commit 2d38bec

File tree

6 files changed

+27
-9
lines changed

6 files changed

+27
-9
lines changed

clang/lib/AST/Interp/ByteCodeEmitter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class ByteCodeEmitter {
4646
/// Methods implemented by the compiler.
4747
virtual bool visitFunc(const FunctionDecl *E) = 0;
4848
virtual bool visitExpr(const Expr *E) = 0;
49-
virtual bool visitDecl(const VarDecl *E) = 0;
49+
virtual bool visitDecl(const VarDecl *E, bool ConstantContext) = 0;
5050

5151
/// Emits jumps.
5252
bool jumpTrue(const LabelTy &Label);

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3223,9 +3223,21 @@ bool ByteCodeExprGen<Emitter>::visitExpr(const Expr *E) {
32233223
/// We get here from evaluateAsInitializer().
32243224
/// We need to evaluate the initializer and return its value.
32253225
template <class Emitter>
3226-
bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
3226+
bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD,
3227+
bool ConstantContext) {
32273228
assert(!VD->isInvalidDecl() && "Trying to constant evaluate an invalid decl");
32283229

3230+
std::optional<PrimType> VarT = classify(VD->getType());
3231+
3232+
// We only create variables if we're evaluating in a constant context.
3233+
// Otherwise, just evaluate the initializer and return it.
3234+
if (!ConstantContext) {
3235+
DeclScope<Emitter> LocalScope(this, VD);
3236+
if (!this->visit(VD->getAnyInitializer()))
3237+
return false;
3238+
return this->emitRet(VarT.value_or(PT_Ptr), VD);
3239+
}
3240+
32293241
// If we've seen the global variable already and the initializer failed,
32303242
// just return false immediately.
32313243
if (std::optional<unsigned> Index = P.getGlobal(VD)) {
@@ -3241,7 +3253,6 @@ bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
32413253
if (!this->visitVarDecl(VD))
32423254
return false;
32433255

3244-
std::optional<PrimType> VarT = classify(VD->getType());
32453256
// Get a pointer to the variable
32463257
if (Context::shouldBeGloballyIndexed(VD)) {
32473258
auto GlobalIndex = P.getGlobal(VD);

clang/lib/AST/Interp/ByteCodeExprGen.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
133133

134134
protected:
135135
bool visitExpr(const Expr *E) override;
136-
bool visitDecl(const VarDecl *VD) override;
136+
bool visitDecl(const VarDecl *VD, bool ConstantContext) override;
137137

138138
protected:
139139
/// Emits scope cleanup instructions.

clang/lib/AST/Interp/EvalEmitter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
6666

6767
EvalResult.setSource(VD);
6868

69-
if (!this->visitDecl(VD) && EvalResult.empty())
69+
if (!this->visitDecl(VD, S.inConstantContext()) && EvalResult.empty())
7070
EvalResult.setInvalid();
7171

7272
return std::move(this->EvalResult);

clang/lib/AST/Interp/EvalEmitter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class EvalEmitter : public SourceMapper {
5555

5656
/// Methods implemented by the compiler.
5757
virtual bool visitExpr(const Expr *E) = 0;
58-
virtual bool visitDecl(const VarDecl *VD) = 0;
58+
virtual bool visitDecl(const VarDecl *VD, bool ConstantContext) = 0;
5959

6060
/// Emits jumps.
6161
bool jumpTrue(const LabelTy &Label);

clang/lib/AST/Interp/EvaluationResult.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,16 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
124124
for (const Record::Base &B : R->bases()) {
125125
Pointer P = BasePtr.atField(B.Offset);
126126
if (!P.isInitialized()) {
127-
S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(),
128-
diag::note_constexpr_uninitialized_base)
129-
<< B.Desc->getType();
127+
const Descriptor *Desc = BasePtr.getDeclDesc();
128+
if (Desc->asDecl())
129+
S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(),
130+
diag::note_constexpr_uninitialized_base)
131+
<< B.Desc->getType();
132+
else
133+
S.FFDiag(BasePtr.getDeclDesc()->asExpr()->getExprLoc(),
134+
diag::note_constexpr_uninitialized_base)
135+
<< B.Desc->getType();
136+
130137
return false;
131138
}
132139
Result &= CheckFieldsInitialized(S, Loc, P, B.R);

0 commit comments

Comments
 (0)