[clang] 569222e - [clang][Interp] Only check constructors for global variables

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 2 00:23:47 PST 2023


Author: Timm Bäder
Date: 2023-03-02T09:13:47+01:00
New Revision: 569222e172e5d28d66e9607325475b107cee20cb

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

LOG: [clang][Interp] Only check constructors for global variables

Local variables may be partially initialized.

Differential Revision: https://reviews.llvm.org/D140723

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeExprGen.h
    clang/lib/AST/Interp/Interp.cpp
    clang/lib/AST/Interp/Interp.h
    clang/lib/AST/Interp/Opcodes.td
    clang/test/AST/Interp/cxx20.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 7b804b4cad3d..231f39ff8bd6 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -162,6 +162,9 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
     if (!visitInitializer(Init))
       return false;
 
+    if (Init->getType()->isRecordType() && !this->emitCheckGlobalCtor(Init))
+      return false;
+
     return this->emitPopPtr(Init);
   }
 

diff  --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 329cc0ff949d..554e9a8e2d20 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -431,6 +431,15 @@ static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
       Result = false;
     }
   }
+
+  // Check Fields in all bases
+  for (const Record::Base &B : R->bases()) {
+    Pointer P = Pointer(BasePtr.block(), B.Offset);
+    Result &= CheckFieldsInitialized(S, OpPC, P, B.R);
+  }
+
+  // TODO: Virtual bases
+
   return Result;
 }
 

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 99c1bd58acd2..fbf74b54e330 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1455,6 +1455,11 @@ inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
   return true;
 }
 
+inline bool CheckGlobalCtor(InterpState &S, CodePtr &PC) {
+  const Pointer &Obj = S.Stk.peek<Pointer>();
+  return CheckCtorCall(S, PC, Obj);
+}
+
 inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) {
   auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
   Pointer ThisPtr;
@@ -1480,11 +1485,6 @@ inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) {
   if (Interpret(S, CallResult)) {
     NewFrame.release(); // Frame was delete'd already.
     assert(S.Current == FrameBefore);
-
-    // For constructors, check that all fields have been initialized.
-    if (Func->isConstructor() && !CheckCtorCall(S, PC, ThisPtr))
-      return false;
-
     return true;
   }
 

diff  --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index d1ad7adc1edc..1e325055c417 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -328,6 +328,8 @@ def GetLocal : AccessOpcode { let HasCustomEval = 1; }
 // [] -> [Pointer]
 def SetLocal : AccessOpcode { let HasCustomEval = 1; }
 
+def CheckGlobalCtor : Opcode {}
+
 // [] -> [Value]
 def GetGlobal : AccessOpcode;
 // [Value] -> []

diff  --git a/clang/test/AST/Interp/cxx20.cpp b/clang/test/AST/Interp/cxx20.cpp
index 44c97dd1afcd..cc37722730fc 100644
--- a/clang/test/AST/Interp/cxx20.cpp
+++ b/clang/test/AST/Interp/cxx20.cpp
@@ -85,10 +85,11 @@ static_assert(initializedLocal2() == 20); // expected-error {{not an integral co
                                           // ref-note {{in call to}}
 
 
-struct Int { int a; }; // expected-note {{subobject declared here}}
+struct Int { int a; };
 constexpr int initializedLocal3() {
-  Int i; // expected-note {{subobject of type 'int' is not initialized}}
-  return i.a; // ref-note {{read of uninitialized object is not allowed in a constant expression}}
+  Int i;
+  return i.a; // ref-note {{read of uninitialized object is not allowed in a constant expression}} \
+              // expected-note {{read of object outside its lifetime}}
 }
 static_assert(initializedLocal3() == 20); // expected-error {{not an integral constant expression}} \
                                           // expected-note {{in call to}} \
@@ -157,21 +158,19 @@ namespace UninitializedFields {
 
   class Derived : public Base {
   public:
-    constexpr Derived() : Base() {} // expected-note {{subobject of type 'int' is not initialized}}
-  };
+    constexpr Derived() : Base() {}   };
 
-constexpr Derived D; // expected-error {{must be initialized by a constant expression}} \\
-                     // expected-note {{in call to 'Derived()'}} \
-                     // ref-error {{must be initialized by a constant expression}} \
-                     // ref-note {{subobject of type 'int' is not initialized}}
+  constexpr Derived D; // expected-error {{must be initialized by a constant expression}} \
+                       // expected-note {{subobject of type 'int' is not initialized}} \
+                       // ref-error {{must be initialized by a constant expression}} \
+                       // ref-note {{subobject of type 'int' is not initialized}}
 
   class C2 {
   public:
     A a;
-    constexpr C2() {} // expected-note {{subobject of type 'int' is not initialized}}
-  };
+    constexpr C2() {}   };
   constexpr C2 c2; // expected-error {{must be initialized by a constant expression}} \
-                   // expected-note {{in call to 'C2()'}} \
+                   // expected-note {{subobject of type 'int' is not initialized}} \
                    // ref-error {{must be initialized by a constant expression}} \
                    // ref-note {{subobject of type 'int' is not initialized}}
 


        


More information about the cfe-commits mailing list