diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -162,6 +162,9 @@ 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.h b/clang/lib/AST/Interp/Interp.h --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1455,6 +1455,11 @@ return true; } +inline bool CheckGlobalCtor(InterpState &S, CodePtr &PC) { + const Pointer &Obj = S.Stk.peek(); + return CheckCtorCall(S, PC, Obj); +} + inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) { auto NewFrame = std::make_unique(S, Func, PC); Pointer ThisPtr; @@ -1480,11 +1485,6 @@ 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/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -431,6 +431,15 @@ 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/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -328,6 +328,8 @@ // [] -> [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 --- a/clang/test/AST/Interp/cxx20.cpp +++ b/clang/test/AST/Interp/cxx20.cpp @@ -85,10 +85,11 @@ // 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 @@ 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}}