Skip to content

Commit aa7c5c9

Browse files
committed
[clang][Interp] Handle missing local initializers better
This is illegal in a constexpr context. We can already figure that out, but we'd still run into an assertion later on when trying to visit the missing initializer or run the invalid function. Differential Revision: https://reviews.llvm.org/D132832
1 parent 5c4dbff commit aa7c5c9

File tree

5 files changed

+36
-5
lines changed

5 files changed

+36
-5
lines changed

clang/lib/AST/Interp/ByteCodeEmitter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,10 @@ Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) {
6262
// Return a dummy function if compilation failed.
6363
if (BailLocation)
6464
return llvm::make_error<ByteCodeGenError>(*BailLocation);
65-
else
65+
else {
66+
Func->setIsFullyCompiled(true);
6667
return Func;
68+
}
6769
} else {
6870
// Create scopes from descriptors.
6971
llvm::SmallVector<Scope, 2> Scopes;
@@ -74,6 +76,7 @@ Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) {
7476
// Set the function's code.
7577
Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
7678
std::move(Scopes));
79+
Func->setIsFullyCompiled(true);
7780
return Func;
7881
}
7982
}

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,14 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
612612
}
613613
assert(Func);
614614

615+
// If the function is being compiled right now, this is a recursive call.
616+
// In that case, the function can't be valid yet, even though it will be
617+
// later.
618+
// If the function is already fully compiled but not constexpr, it was
619+
// found to be faulty earlier on, so bail out.
620+
if (Func->isFullyCompiled() && !Func->isConstexpr())
621+
return false;
622+
615623
QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
616624
Optional<PrimType> T = classify(ReturnType);
617625

clang/lib/AST/Interp/ByteCodeStmtGen.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,16 @@ bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
241241

242242
// Integers, pointers, primitives.
243243
if (Optional<PrimType> T = this->classify(DT)) {
244+
const Expr *Init = VD->getInit();
245+
246+
if (!Init)
247+
return false;
248+
244249
auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified());
245-
// Compile the initialiser in its own scope.
250+
// Compile the initializer in its own scope.
246251
{
247252
ExprScope<Emitter> Scope(this);
248-
if (!this->visit(VD->getInit()))
253+
if (!this->visit(Init))
249254
return false;
250255
}
251256
// Set the value.

clang/lib/AST/Interp/Function.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ class Function {
112112
/// Checks if the function is a constructor.
113113
bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
114114

115+
/// Checks if the function is fully done compiling.
116+
bool isFullyCompiled() const { return IsFullyCompiled; }
117+
115118
private:
116119
/// Construct a function representing an actual function.
117120
Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
@@ -128,6 +131,8 @@ class Function {
128131
IsValid = true;
129132
}
130133

134+
void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
135+
131136
private:
132137
friend class Program;
133138
friend class ByteCodeEmitter;
@@ -154,6 +159,9 @@ class Function {
154159
llvm::DenseMap<unsigned, ParamDescriptor> Params;
155160
/// Flag to indicate if the function is valid.
156161
bool IsValid = false;
162+
/// Flag to indicate if the function is done being
163+
/// compiled to bytecode.
164+
bool IsFullyCompiled = false;
157165

158166
public:
159167
/// Dumps the disassembled bytecode to \c llvm::errs().

clang/test/AST/Interp/cxx20.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// RUN: %clang_cc1 -std=c++20 -verify=ref %s
33

44

5-
// expected-no-diagnostics
6-
// ref-no-diagnostics
75
constexpr int getMinus5() {
86
int a = 10;
97
a = -5;
@@ -53,3 +51,12 @@ constexpr int pointerAssign2() {
5351
return v;
5452
}
5553
static_assert(pointerAssign2() == 12, "");
54+
55+
56+
constexpr int unInitLocal() {
57+
int a;
58+
return a; // ref-note{{read of uninitialized object}}
59+
}
60+
static_assert(unInitLocal() == 0, ""); // expected-error {{not an integral constant expression}} \
61+
// ref-error {{not an integral constant expression}} \
62+
// ref-note {{in call to 'unInitLocal()'}}

0 commit comments

Comments
 (0)