Skip to content

Commit b549c6a

Browse files
committed
EvaluationResult
1 parent 12e425d commit b549c6a

19 files changed

+599
-339
lines changed

clang/lib/AST/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ add_clang_library(clangAST
7575
Interp/Function.cpp
7676
Interp/InterpBuiltin.cpp
7777
Interp/Floating.cpp
78+
Interp/EvaluationResult.cpp
7879
Interp/Interp.cpp
7980
Interp/InterpBlock.cpp
8081
Interp/InterpFrame.cpp

clang/lib/AST/ExprConstant.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15439,11 +15439,13 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
1543915439
if (Info.EnableNewConstInterp) {
1544015440
if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result))
1544115441
return false;
15442-
} else {
15443-
if (!::Evaluate(Result, Info, E))
15444-
return false;
15442+
return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result,
15443+
ConstantExprKind::Normal);
1544515444
}
1544615445

15446+
if (!::Evaluate(Result, Info, E))
15447+
return false;
15448+
1544715449
// Implicit lvalue-to-rvalue cast.
1544815450
if (E->isGLValue()) {
1544915451
LValue LV;
@@ -15671,6 +15673,13 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
1567115673
EvalInfo Info(Ctx, Result, EM);
1567215674
Info.InConstantContext = true;
1567315675

15676+
if (Info.EnableNewConstInterp) {
15677+
if (!Info.Ctx.getInterpContext().evaluate(Info, this, Result.Val))
15678+
return false;
15679+
return CheckConstantExpression(Info, getExprLoc(),
15680+
getStorageType(Ctx, this), Result.Val, Kind);
15681+
}
15682+
1567415683
// The type of the object we're initializing is 'const T' for a class NTTP.
1567515684
QualType T = getType();
1567615685
if (Kind == ConstantExprKind::ClassTemplateArgument)
@@ -15746,10 +15755,16 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
1574615755
Info.setEvaluatingDecl(VD, Value);
1574715756
Info.InConstantContext = IsConstantInitialization;
1574815757

15758+
SourceLocation DeclLoc = VD->getLocation();
15759+
QualType DeclTy = VD->getType();
15760+
1574915761
if (Info.EnableNewConstInterp) {
1575015762
auto &InterpCtx = const_cast<ASTContext &>(Ctx).getInterpContext();
1575115763
if (!InterpCtx.evaluateAsInitializer(Info, VD, Value))
1575215764
return false;
15765+
15766+
return CheckConstantExpression(Info, DeclLoc, DeclTy, Value,
15767+
ConstantExprKind::Normal);
1575315768
} else {
1575415769
LValue LVal;
1575515770
LVal.set(VD);
@@ -15779,8 +15794,6 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
1577915794
llvm_unreachable("Unhandled cleanup; missing full expression marker?");
1578015795
}
1578115796

15782-
SourceLocation DeclLoc = VD->getLocation();
15783-
QualType DeclTy = VD->getType();
1578415797
return CheckConstantExpression(Info, DeclLoc, DeclTy, Value,
1578515798
ConstantExprKind::Normal) &&
1578615799
CheckMemoryLeaks(Info);

clang/lib/AST/Interp/ByteCodeEmitter.cpp

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@
2020
using namespace clang;
2121
using namespace clang::interp;
2222

23-
Expected<Function *>
24-
ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
23+
Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
2524
// Set up argument indices.
2625
unsigned ParamOffset = 0;
2726
SmallVector<PrimType, 8> ParamTypes;
@@ -120,10 +119,6 @@ ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
120119

121120
// Compile the function body.
122121
if (!IsEligibleForCompilation || !visitFunc(FuncDecl)) {
123-
// Return a dummy function if compilation failed.
124-
if (BailLocation)
125-
return llvm::make_error<ByteCodeGenError>(*BailLocation);
126-
127122
Func->setIsFullyCompiled(true);
128123
return Func;
129124
}
@@ -183,12 +178,6 @@ int32_t ByteCodeEmitter::getOffset(LabelTy Label) {
183178
return 0ull;
184179
}
185180

186-
bool ByteCodeEmitter::bail(const SourceLocation &Loc) {
187-
if (!BailLocation)
188-
BailLocation = Loc;
189-
return false;
190-
}
191-
192181
/// Helper to write bytecode and bail out if 32-bit offsets become invalid.
193182
/// Pointers will be automatically marshalled as 32-bit IDs.
194183
template <typename T>

clang/lib/AST/Interp/ByteCodeEmitter.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include "PrimType.h"
1818
#include "Program.h"
1919
#include "Source.h"
20-
#include "llvm/Support/Error.h"
2120

2221
namespace clang {
2322
namespace interp {
@@ -32,7 +31,7 @@ class ByteCodeEmitter {
3231

3332
public:
3433
/// Compiles the function into the module.
35-
llvm::Expected<Function *> compileFunc(const FunctionDecl *FuncDecl);
34+
Function *compileFunc(const FunctionDecl *FuncDecl);
3635

3736
protected:
3837
ByteCodeEmitter(Context &Ctx, Program &P) : Ctx(Ctx), P(P) {}
@@ -49,11 +48,6 @@ class ByteCodeEmitter {
4948
virtual bool visitExpr(const Expr *E) = 0;
5049
virtual bool visitDecl(const VarDecl *E) = 0;
5150

52-
/// Bails out if a given node cannot be compiled.
53-
bool bail(const Stmt *S) { return bail(S->getBeginLoc()); }
54-
bool bail(const Decl *D) { return bail(D->getBeginLoc()); }
55-
bool bail(const SourceLocation &Loc);
56-
5751
/// Emits jumps.
5852
bool jumpTrue(const LabelTy &Label);
5953
bool jumpFalse(const LabelTy &Label);
@@ -81,8 +75,6 @@ class ByteCodeEmitter {
8175
LabelTy NextLabel = 0;
8276
/// Offset of the next local variable.
8377
unsigned NextLocalOffset = 0;
84-
/// Location of a failure.
85-
std::optional<SourceLocation> BailLocation;
8678
/// Label information for linker.
8779
llvm::DenseMap<LabelTy, unsigned> LabelOffsets;
8880
/// Location of label relocations.

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
371371
}
372372

373373
if (!LT || !RT || !T)
374-
return this->bail(BO);
374+
return false;
375375

376376
// Pointer arithmetic special case.
377377
if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) {
@@ -451,7 +451,7 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
451451
case BO_LAnd:
452452
llvm_unreachable("Already handled earlier");
453453
default:
454-
return this->bail(BO);
454+
return false;
455455
}
456456

457457
llvm_unreachable("Unhandled binary op");
@@ -504,7 +504,7 @@ bool ByteCodeExprGen<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) {
504504
else if (Op == BO_Sub)
505505
return this->emitSubOffset(OffsetType, E);
506506

507-
return this->bail(E);
507+
return false;
508508
}
509509

510510
template <class Emitter>
@@ -2358,7 +2358,9 @@ bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
23582358
// Return the value
23592359
if (VarT)
23602360
return this->emitRet(*VarT, VD);
2361-
return this->emitRetValue(VD);
2361+
2362+
// Return non-primitive values as pointers here.
2363+
return this->emitRet(PT_Ptr, VD);
23622364
}
23632365

23642366
template <class Emitter>
@@ -2378,7 +2380,7 @@ bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
23782380
std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init);
23792381

23802382
if (!GlobalIndex)
2381-
return this->bail(VD);
2383+
return false;
23822384

23832385
assert(Init);
23842386
{

clang/lib/AST/Interp/ByteCodeExprGen.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,6 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
191191
if (!visitInitializer(Init))
192192
return false;
193193

194-
if ((Init->getType()->isArrayType() || Init->getType()->isRecordType()) &&
195-
!this->emitCheckGlobalCtor(Init))
196-
return false;
197-
198194
return this->emitPopPtr(Init);
199195
}
200196

clang/lib/AST/Interp/ByteCodeStmtGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
262262
default: {
263263
if (auto *Exp = dyn_cast<Expr>(S))
264264
return this->discard(Exp);
265-
return this->bail(S);
265+
return false;
266266
}
267267
}
268268
}

clang/lib/AST/Interp/Context.cpp

Lines changed: 73 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,8 @@ Context::~Context() {}
3030
bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
3131
assert(Stk.empty());
3232
Function *Func = P->getFunction(FD);
33-
if (!Func || !Func->hasBody()) {
34-
if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) {
35-
Func = *R;
36-
} else {
37-
handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) {
38-
Parent.FFDiag(Err.getRange().getBegin(),
39-
diag::err_experimental_clang_interp_failed)
40-
<< Err.getRange();
41-
});
42-
return false;
43-
}
44-
}
33+
if (!Func || !Func->hasBody())
34+
Func = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD);
4535

4636
APValue DummyResult;
4737
if (!Run(Parent, Func, DummyResult)) {
@@ -54,36 +44,90 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
5444
bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
5545
assert(Stk.empty());
5646
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
57-
if (Check(Parent, C.interpretExpr(E))) {
58-
assert(Stk.empty());
59-
#ifndef NDEBUG
60-
// Make sure we don't rely on some value being still alive in
61-
// InterpStack memory.
47+
48+
auto Res = C.interpretExpr(E);
49+
50+
if (Res.isInvalid()) {
6251
Stk.clear();
52+
return false;
53+
}
54+
55+
assert(Stk.empty());
56+
#ifndef NDEBUG
57+
// Make sure we don't rely on some value being still alive in
58+
// InterpStack memory.
59+
Stk.clear();
6360
#endif
64-
return true;
61+
62+
// Implicit lvalue-to-rvalue conversion.
63+
if (E->isGLValue()) {
64+
std::optional<APValue> RValueResult = Res.toRValue();
65+
if (!RValueResult) {
66+
return false;
67+
}
68+
Result = *RValueResult;
69+
} else {
70+
Result = Res.toAPValue();
6571
}
6672

73+
return true;
74+
}
75+
76+
bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) {
77+
assert(Stk.empty());
78+
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
79+
80+
auto Res = C.interpretExpr(E);
81+
if (Res.isInvalid()) {
82+
Stk.clear();
83+
return false;
84+
}
85+
86+
assert(Stk.empty());
87+
#ifndef NDEBUG
88+
// Make sure we don't rely on some value being still alive in
89+
// InterpStack memory.
6790
Stk.clear();
68-
return false;
91+
#endif
92+
Result = Res.toAPValue();
93+
return true;
6994
}
7095

7196
bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
7297
APValue &Result) {
7398
assert(Stk.empty());
7499
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
75-
if (Check(Parent, C.interpretDecl(VD))) {
76-
assert(Stk.empty());
77-
#ifndef NDEBUG
78-
// Make sure we don't rely on some value being still alive in
79-
// InterpStack memory.
100+
101+
auto Res = C.interpretDecl(VD);
102+
if (Res.isInvalid()) {
80103
Stk.clear();
81-
#endif
82-
return true;
104+
return false;
83105
}
84106

107+
assert(Stk.empty());
108+
#ifndef NDEBUG
109+
// Make sure we don't rely on some value being still alive in
110+
// InterpStack memory.
85111
Stk.clear();
86-
return false;
112+
#endif
113+
114+
// Ensure global variables are fully initialized.
115+
if (shouldBeGloballyIndexed(VD) && !Res.isInvalid() &&
116+
(VD->getType()->isRecordType() || VD->getType()->isArrayType())) {
117+
assert(Res.isLValue());
118+
119+
if (!Res.checkFullyInitialized(C.getState()))
120+
return false;
121+
122+
// lvalue-to-rvalue conversion.
123+
std::optional<APValue> RValueResult = Res.toRValue();
124+
if (!RValueResult)
125+
return false;
126+
Result = *RValueResult;
127+
128+
} else
129+
Result = Res.toAPValue();
130+
return true;
87131
}
88132

89133
const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }
@@ -234,12 +278,8 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FD) {
234278
return Func;
235279

236280
if (!Func || WasNotDefined) {
237-
if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD))
238-
Func = *R;
239-
else {
240-
llvm::consumeError(R.takeError());
241-
return nullptr;
242-
}
281+
if (auto F = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD))
282+
Func = F;
243283
}
244284

245285
return Func;

clang/lib/AST/Interp/Context.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ class Context final {
5151
/// Evaluates a toplevel expression as an rvalue.
5252
bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result);
5353

54+
/// Like evaluateAsRvalue(), but does no implicit lvalue-to-rvalue conversion.
55+
bool evaluate(State &Parent, const Expr *E, APValue &Result);
56+
5457
/// Evaluates a toplevel initializer.
5558
bool evaluateAsInitializer(State &Parent, const VarDecl *VD, APValue &Result);
5659

0 commit comments

Comments
 (0)