[clang] 9ece3eb - [clang][Interp] Check ConstantExpr results for initialization

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 7 04:30:08 PDT 2024


Author: Timm Bäder
Date: 2024-06-07T13:29:23+02:00
New Revision: 9ece3eb1459309f9fbd18ce8ec8f771c238e8815

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

LOG: [clang][Interp] Check ConstantExpr results for initialization

They need to be fully initialized, similar to global variables.

Added: 
    

Modified: 
    clang/lib/AST/Interp/EvalEmitter.cpp
    clang/lib/AST/Interp/EvaluationResult.cpp
    clang/test/AST/Interp/cxx20.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index 6d8aa3f20f01f..f6191d8ed6345 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -41,6 +41,7 @@ EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
                                             bool ConvertResultToRValue) {
   S.setEvalLocation(E->getExprLoc());
   this->ConvertResultToRValue = ConvertResultToRValue;
+  this->CheckFullyInitialized = isa<ConstantExpr>(E);
   EvalResult.setSource(E);
 
   if (!this->visitExpr(E)) {
@@ -175,6 +176,10 @@ bool EvalEmitter::emitRetVoid(const SourceInfo &Info) {
 
 bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
   const auto &Ptr = S.Stk.pop<Pointer>();
+
+  if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
+    return false;
+
   if (std::optional<APValue> APV = Ptr.toRValue(S.getCtx())) {
     EvalResult.setValue(*APV);
     return true;

diff  --git a/clang/lib/AST/Interp/EvaluationResult.cpp b/clang/lib/AST/Interp/EvaluationResult.cpp
index c04b0fc0a1121..29977232975fc 100644
--- a/clang/lib/AST/Interp/EvaluationResult.cpp
+++ b/clang/lib/AST/Interp/EvaluationResult.cpp
@@ -141,16 +141,14 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S,
                                              const Pointer &Ptr) const {
   assert(Source);
   assert(empty());
-
-  // Our Source must be a VarDecl.
-  const Decl *SourceDecl = Source.dyn_cast<const Decl *>();
-  assert(SourceDecl);
-  const auto *VD = cast<VarDecl>(SourceDecl);
-  assert(VD->getType()->isRecordType() || VD->getType()->isArrayType());
-  SourceLocation InitLoc = VD->getAnyInitializer()->getExprLoc();
-
   assert(!Ptr.isZero());
 
+  SourceLocation InitLoc;
+  if (const auto *D = Source.dyn_cast<const Decl *>())
+    InitLoc = cast<VarDecl>(D)->getAnyInitializer()->getExprLoc();
+  else if (const auto *E = Source.dyn_cast<const Expr *>())
+    InitLoc = E->getExprLoc();
+
   if (const Record *R = Ptr.getRecord())
     return CheckFieldsInitialized(S, InitLoc, Ptr, R);
   const auto *CAT =

diff  --git a/clang/test/AST/Interp/cxx20.cpp b/clang/test/AST/Interp/cxx20.cpp
index c750be866ca7c..434823644a7a3 100644
--- a/clang/test/AST/Interp/cxx20.cpp
+++ b/clang/test/AST/Interp/cxx20.cpp
@@ -797,3 +797,20 @@ namespace self_referencing {
     S s(1);
   }
 }
+
+namespace GH64949 {
+  struct f {
+    int g; // both-note {{subobject declared here}}
+    constexpr ~f() {}
+  };
+
+  class h {
+  public:
+    consteval h(char *) {}
+    f i;
+  };
+
+  void test() { h{nullptr}; } // both-error {{call to consteval function 'GH64949::h::h' is not a constant expression}} \
+                              // both-note {{subobject 'g' is not initialized}} \
+                              // both-warning {{expression result unused}}
+}


        


More information about the cfe-commits mailing list