Skip to content

Commit 909309e

Browse files
committed
[clang][bytecode] Use bytecode interprete in isPotentialConstantExprUnevaluated
Fake a function call to the given function and evaluate the given expression as if it was part of that function call.
1 parent 3bb4355 commit 909309e

File tree

12 files changed

+62
-3
lines changed

12 files changed

+62
-3
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6670,6 +6670,11 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
66706670
}
66716671
// Function parameters.
66726672
if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
6673+
if (Ctx.getLangOpts().CPlusPlus && !Ctx.getLangOpts().CPlusPlus11 &&
6674+
!D->getType()->isIntegralOrEnumerationType()) {
6675+
return this->emitInvalidDeclRef(cast<DeclRefExpr>(E),
6676+
/*InitializerFailed=*/false, E);
6677+
}
66736678
if (auto It = this->Params.find(PVD); It != this->Params.end()) {
66746679
if (IsReference || !It->second.IsPtr)
66756680
return this->emitGetParam(classifyPrim(E), It->second.Offset, E);

clang/lib/AST/ByteCode/Context.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,19 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
5252
return Func->isValid();
5353
}
5454

55+
void Context::isPotentialConstantExprUnevaluated(State &Parent, const Expr *E,
56+
const FunctionDecl *FD) {
57+
assert(Stk.empty());
58+
++EvalID;
59+
size_t StackSizeBefore = Stk.size();
60+
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
61+
62+
if (!C.interpretCall(FD, E)) {
63+
C.cleanup();
64+
Stk.clearTo(StackSizeBefore);
65+
}
66+
}
67+
5568
bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
5669
++EvalID;
5770
bool Recursing = !Stk.empty();

clang/lib/AST/ByteCode/Context.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ class Context final {
4747
~Context();
4848

4949
/// Checks if a function is a potential constant expression.
50-
bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FnDecl);
50+
bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FD);
51+
void isPotentialConstantExprUnevaluated(State &Parent, const Expr *E,
52+
const FunctionDecl *FD);
5153

5254
/// Evaluates a toplevel expression as an rvalue.
5355
bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result);

clang/lib/AST/ByteCode/EvalEmitter.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,19 @@ EvaluationResult EvalEmitter::interpretAsPointer(const Expr *E,
9090
return std::move(this->EvalResult);
9191
}
9292

93+
bool EvalEmitter::interpretCall(const FunctionDecl *FD, const Expr *E) {
94+
// Add parameters to the parameter map. The values in the ParamOffset don't
95+
// matter in this case as reading from them can't ever work.
96+
for (const ParmVarDecl *PD : FD->parameters()) {
97+
this->Params.insert({PD, {0, false}});
98+
}
99+
100+
if (!this->visit(E))
101+
return false;
102+
PrimType T = Ctx.classify(E).value_or(PT_Ptr);
103+
return this->emitPop(T, E);
104+
}
105+
93106
void EvalEmitter::emitLabel(LabelTy Label) { CurrentLabel = Label; }
94107

95108
EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; }

clang/lib/AST/ByteCode/EvalEmitter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ class EvalEmitter : public SourceMapper {
4040
EvaluationResult interpretDecl(const VarDecl *VD, bool CheckFullyInitialized);
4141
/// Interpret the given Expr to a Pointer.
4242
EvaluationResult interpretAsPointer(const Expr *E, PtrCallback PtrCB);
43+
/// Interpret the given expression as if it was in the body of the given
44+
/// function, i.e. the parameters of the function are available for use.
45+
bool interpretCall(const FunctionDecl *FD, const Expr *E);
4346

4447
/// Clean up all resources.
4548
void cleanup();

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,12 @@ static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,
142142
return false;
143143

144144
if (isa<ParmVarDecl>(D)) {
145-
if (D->getType()->isReferenceType())
145+
if (D->getType()->isReferenceType()) {
146+
if (S.inConstantContext() && S.getLangOpts().CPlusPlus &&
147+
!S.getLangOpts().CPlusPlus11)
148+
diagnoseNonConstVariable(S, OpPC, D);
146149
return false;
150+
}
147151

148152
const SourceInfo &Loc = S.Current->getSource(OpPC);
149153
if (S.getLangOpts().CPlusPlus11) {
@@ -658,6 +662,9 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
658662
if (Ptr.isInitialized())
659663
return true;
660664

665+
if (Ptr.isExtern() && S.checkingPotentialConstantExpression())
666+
return false;
667+
661668
if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
662669
VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {
663670

clang/lib/AST/ByteCode/Interp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1308,7 +1308,7 @@ bool Dup(InterpState &S, CodePtr OpPC) {
13081308

13091309
template <PrimType Name, class T = typename PrimConv<Name>::T>
13101310
bool Pop(InterpState &S, CodePtr OpPC) {
1311-
S.Stk.pop<T>();
1311+
S.Stk.discard<T>();
13121312
return true;
13131313
}
13141314

clang/lib/AST/ExprConstant.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18018,6 +18018,11 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
1801818018
Info.InConstantContext = true;
1801918019
Info.CheckingPotentialConstantExpression = true;
1802018020

18021+
if (Info.EnableNewConstInterp) {
18022+
Info.Ctx.getInterpContext().isPotentialConstantExprUnevaluated(Info, E, FD);
18023+
return Diags.empty();
18024+
}
18025+
1802118026
// Fabricate a call stack frame to give the arguments a plausible cover story.
1802218027
CallStackFrame Frame(Info, SourceLocation(), FD, /*This=*/nullptr,
1802318028
/*CallExpr=*/nullptr, CallRef());

clang/test/AST/ByteCode/builtin-constant-p.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,11 @@ void test17(void) {
140140
F("string literal" + 1); // both-warning {{adding}} \
141141
// both-note {{use array indexing}}
142142
}
143+
144+
/// FIXME
145+
static void foo(int i) __attribute__((__diagnose_if__(!__builtin_constant_p(i), "not constant", "error"))) // expected-note {{from}}
146+
{
147+
}
148+
static void bar(int i) {
149+
foo(15); // expected-error {{not constant}}
150+
}

clang/test/Sema/diagnose_if.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 %s -verify -fno-builtin
2+
// RUN: %clang_cc1 %s -verify -fno-builtin -fexperimental-new-constant-interpreter
23

34
#define _diagnose_if(...) __attribute__((diagnose_if(__VA_ARGS__)))
45

0 commit comments

Comments
 (0)