Author: Timm Baeder Date: 2023-10-03T06:46:31+02:00 New Revision: f58d54ab969b2f342a882dfb03334f18f4ec1dcc
URL: https://github.com/llvm/llvm-project/commit/f58d54ab969b2f342a882dfb03334f18f4ec1dcc DIFF: https://github.com/llvm/llvm-project/commit/f58d54ab969b2f342a882dfb03334f18f4ec1dcc.diff LOG: [clang][Interp] Diagnose uninitialized bases (#67131) Added: clang/test/AST/Interp/constexpr-subobj-initialization.cpp Modified: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeStmtGen.cpp clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Opcodes.td Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index e266804a4e75dea..f4ab30a5c8e7238 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -561,7 +561,7 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, if (!this->visitInitializer(Init)) return false; - if (!this->emitPopPtr(E)) + if (!this->emitInitPtrPop(E)) return false; // Base initializers don't increase InitIndex, since they don't count // into the Record's fields. @@ -1718,7 +1718,7 @@ bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R, return false; if (!this->visitZeroRecordInitializer(B.R, E)) return false; - if (!this->emitPopPtr(E)) + if (!this->emitInitPtrPop(E)) return false; } diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp index 15eae8e20b3a678..a81c82c38955e9c 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -191,7 +191,7 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) { return false; if (!this->visitInitializer(InitExpr)) return false; - if (!this->emitPopPtr(InitExpr)) + if (!this->emitInitPtrPop(InitExpr)) return false; } } diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index e1951574edb6288..8e851595963184c 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -467,6 +467,12 @@ static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC, // Check Fields in all bases for (const Record::Base &B : R->bases()) { Pointer P = BasePtr.atField(B.Offset); + if (!P.isInitialized()) { + S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(), + diag::note_constexpr_uninitialized_base) + << B.Desc->getType(); + return false; + } Result &= CheckFieldsInitialized(S, OpPC, P, B.R); } diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 9d5ec3315415cf7..d62e64bedb213ac 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1245,6 +1245,12 @@ inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) { return true; } +inline bool InitPtrPop(InterpState &S, CodePtr OpPC) { + const Pointer &Ptr = S.Stk.pop<Pointer>(); + Ptr.initialize(); + return true; +} + inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr) { Pointer Base = Ptr; diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index 9fc4938bb37bde8..50b6c0ac154de30 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -304,6 +304,10 @@ def GetPtrBasePop : Opcode { let Args = [ArgUint32]; } +def InitPtrPop : Opcode { + let Args = []; +} + def GetPtrDerivedPop : Opcode { let Args = [ArgUint32]; } diff --git a/clang/test/AST/Interp/constexpr-subobj-initialization.cpp b/clang/test/AST/Interp/constexpr-subobj-initialization.cpp new file mode 100644 index 000000000000000..4976b165468bd61 --- /dev/null +++ b/clang/test/AST/Interp/constexpr-subobj-initialization.cpp @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter + +/// This is like the version in test/SemaCXX/, but some of the +/// output types and their location has been adapted. +/// Differences: +/// 1) The type of the uninitialized base class is printed WITH the namespace, +/// i.e. 'baseclass_uninit::DelBase' instead of just 'DelBase'. +/// 2) The location is not the base specifier declaration, but the call site +/// of the constructor. + + +namespace baseclass_uninit { +struct DelBase { + constexpr DelBase() = delete; // expected-note {{'DelBase' has been explicitly marked deleted here}} +}; + +struct Foo : DelBase { + constexpr Foo() {}; // expected-error {{call to deleted constructor of 'DelBase'}} +}; +constexpr Foo f; // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{constructor of base class 'baseclass_uninit::DelBase' is not called}} + +struct Bar : Foo { + constexpr Bar() {}; +}; +constexpr Bar bar; // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{constructor of base class 'baseclass_uninit::DelBase' is not called}} + +struct Base {}; +struct A : Base { + constexpr A() : value() {} // expected-error {{member initializer 'value' does not name a non-static data member or base class}} +}; + +constexpr A a; // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{constructor of base class 'baseclass_uninit::Base' is not called}} + + +struct B : Base { + constexpr B() : {} // expected-error {{expected class member or base class name}} +}; + +constexpr B b; // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{constructor of base class 'baseclass_uninit::Base' is not called}} +} // namespace baseclass_uninit + + +struct Foo { + constexpr Foo(); // expected-note 2{{declared here}} +}; + +constexpr Foo ff; // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{undefined constructor 'Foo' cannot be used in a constant expression}} + +struct Bar : protected Foo { + int i; + constexpr Bar() : i(12) {} // expected-note {{undefined constructor 'Foo' cannot be used in a constant expression}} +}; + +constexpr Bar bb; // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{in call to 'Bar()'}} + +template <typename Ty> +struct Baz { + constexpr Baz(); // expected-note {{declared here}} +}; + +struct Quux : Baz<Foo>, private Bar { + int i; + constexpr Quux() : i(12) {} // expected-note {{undefined constructor 'Baz' cannot be used in a constant expression}} +}; + +constexpr Quux qx; // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{in call to 'Quux()'}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits