[clang] aa7c5c9 - [clang][Interp] Handle missing local initializers better

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 7 22:31:55 PDT 2022


Author: Timm Bäder
Date: 2022-09-08T07:31:07+02:00
New Revision: aa7c5c9c4e5e56fc668b055ce40c1a65fae1e38e

URL: https://github.com/llvm/llvm-project/commit/aa7c5c9c4e5e56fc668b055ce40c1a65fae1e38e
DIFF: https://github.com/llvm/llvm-project/commit/aa7c5c9c4e5e56fc668b055ce40c1a65fae1e38e.diff

LOG: [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

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeEmitter.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeStmtGen.cpp
    clang/lib/AST/Interp/Function.h
    clang/test/AST/Interp/cxx20.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
index a69b23fd613c..42a3ab7837f9 100644
--- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -62,8 +62,10 @@ Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) {
     // Return a dummy function if compilation failed.
     if (BailLocation)
       return llvm::make_error<ByteCodeGenError>(*BailLocation);
-    else
+    else {
+      Func->setIsFullyCompiled(true);
       return Func;
+    }
   } else {
     // Create scopes from descriptors.
     llvm::SmallVector<Scope, 2> Scopes;
@@ -74,6 +76,7 @@ Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) {
     // Set the function's code.
     Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
                   std::move(Scopes));
+    Func->setIsFullyCompiled(true);
     return Func;
   }
 }

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index f9dac9a21978..cf4cbde37975 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -612,6 +612,14 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
     }
     assert(Func);
 
+    // If the function is being compiled right now, this is a recursive call.
+    // In that case, the function can't be valid yet, even though it will be
+    // later.
+    // If the function is already fully compiled but not constexpr, it was
+    // found to be faulty earlier on, so bail out.
+    if (Func->isFullyCompiled() && !Func->isConstexpr())
+      return false;
+
     QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
     Optional<PrimType> T = classify(ReturnType);
 

diff  --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index 90e84149b055..f279267bbe1f 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -241,11 +241,16 @@ bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
 
   // Integers, pointers, primitives.
   if (Optional<PrimType> T = this->classify(DT)) {
+    const Expr *Init = VD->getInit();
+
+    if (!Init)
+      return false;
+
     auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified());
-    // Compile the initialiser in its own scope.
+    // Compile the initializer in its own scope.
     {
       ExprScope<Emitter> Scope(this);
-      if (!this->visit(VD->getInit()))
+      if (!this->visit(Init))
         return false;
     }
     // Set the value.

diff  --git a/clang/lib/AST/Interp/Function.h b/clang/lib/AST/Interp/Function.h
index b009167c1bd6..d52560eaceb2 100644
--- a/clang/lib/AST/Interp/Function.h
+++ b/clang/lib/AST/Interp/Function.h
@@ -112,6 +112,9 @@ class Function {
   /// Checks if the function is a constructor.
   bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
 
+  /// Checks if the function is fully done compiling.
+  bool isFullyCompiled() const { return IsFullyCompiled; }
+
 private:
   /// Construct a function representing an actual function.
   Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
@@ -128,6 +131,8 @@ class Function {
     IsValid = true;
   }
 
+  void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
+
 private:
   friend class Program;
   friend class ByteCodeEmitter;
@@ -154,6 +159,9 @@ class Function {
   llvm::DenseMap<unsigned, ParamDescriptor> Params;
   /// Flag to indicate if the function is valid.
   bool IsValid = false;
+  /// Flag to indicate if the function is done being
+  /// compiled to bytecode.
+  bool IsFullyCompiled = false;
 
 public:
   /// Dumps the disassembled bytecode to \c llvm::errs().

diff  --git a/clang/test/AST/Interp/cxx20.cpp b/clang/test/AST/Interp/cxx20.cpp
index 1e43b472793a..e088f6bafb7e 100644
--- a/clang/test/AST/Interp/cxx20.cpp
+++ b/clang/test/AST/Interp/cxx20.cpp
@@ -2,8 +2,6 @@
 // RUN: %clang_cc1 -std=c++20 -verify=ref %s
 
 
-// expected-no-diagnostics
-// ref-no-diagnostics
 constexpr int getMinus5() {
   int a = 10;
   a = -5;
@@ -53,3 +51,12 @@ constexpr int pointerAssign2() {
   return v;
 }
 static_assert(pointerAssign2() == 12, "");
+
+
+constexpr int unInitLocal() {
+  int a;
+  return a; // ref-note{{read of uninitialized object}}
+}
+static_assert(unInitLocal() == 0, ""); // expected-error {{not an integral constant expression}} \
+                                       // ref-error {{not an integral constant expression}} \
+                                       // ref-note {{in call to 'unInitLocal()'}}


        


More information about the cfe-commits mailing list