Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -381,6 +381,8 @@ (`#57081: `_) - Clang no longer emits inappropriate notes about the loss of ``__unaligned`` qualifier on overload resolution, when the actual reason for the failure is loss of other qualifiers. +- Clang contexpr evaluator now displays notes as well as an error when a constructor + of a base class is not called in the constructor of its derived class. Bug Fixes in This Version ------------------------- Index: clang/include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticASTKinds.td +++ clang/include/clang/Basic/DiagnosticASTKinds.td @@ -70,6 +70,8 @@ "is not a constant expression">; def note_constexpr_uninitialized : Note< "subobject %0 is not initialized">; +def note_constexpr_uninitialized_base : Note< + "constructor of base class %0 is not called">; def note_constexpr_static_local : Note< "control flows through the definition of a %select{static|thread_local}0 variable">; def note_constexpr_subobject_declared_here : Note< Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -2415,9 +2415,16 @@ if (const CXXRecordDecl *CD = dyn_cast(RD)) { unsigned BaseIndex = 0; for (const CXXBaseSpecifier &BS : CD->bases()) { - if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(), - Value.getStructBase(BaseIndex), Kind, - /*SubobjectDecl=*/nullptr, CheckedTemps)) + const APValue &BaseValue = Value.getStructBase(BaseIndex); + if (!BaseValue.hasValue()) { + SourceLocation TypeBeginLoc = BS.getBaseTypeLoc(); + Info.FFDiag(TypeBeginLoc, diag::note_constexpr_uninitialized_base) + << BS.getType() << SourceRange(TypeBeginLoc, BS.getEndLoc()); + return false; + } + if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(), BaseValue, + Kind, /*SubobjectDecl=*/nullptr, + CheckedTemps)) return false; ++BaseIndex; } Index: clang/test/Misc/constexpr-subobj-init-source-ranges.cpp =================================================================== --- /dev/null +++ clang/test/Misc/constexpr-subobj-init-source-ranges.cpp @@ -0,0 +1,11 @@ +// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-print-source-range-info %s 2>&1 | FileCheck %s --strict-whitespace + +struct DelBase { + constexpr DelBase() = delete; +}; + +// CHECK: :{[[@LINE+1]]:21-[[@LINE+1]]:28} +struct Foo : public DelBase { + constexpr Foo() {}; +}; +constexpr Foo f; Index: clang/test/SemaCXX/constexpr-subobj-initialization.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/constexpr-subobj-initialization.cpp @@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +namespace baseclass_uninit { +struct DelBase { + constexpr DelBase() = delete; // expected-note {{'DelBase' has been explicitly marked deleted here}} +}; + +struct Foo : DelBase { // expected-note 2{{constructor of base class 'DelBase' is not called}} + constexpr Foo() {}; // expected-error {{call to deleted constructor of 'DelBase'}} +}; +constexpr Foo f; // expected-error {{must be initialized by a constant expression}} +struct Bar : Foo { + constexpr Bar() {}; +}; +constexpr Bar bar; // expected-error {{must be initialized by a constant expression}} + +struct Base {}; +struct A : Base { // expected-note {{constructor of base class 'Base' is not called}} + 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}} + +struct B : Base { // expected-note {{constructor of base class 'Base' is not called}} + constexpr B() : {} // expected-error {{expected class member or base class name}} +}; + +constexpr B b; // expected-error {{must be initialized by a constant expression}} +} // 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 +struct Baz { + constexpr Baz(); // expected-note {{declared here}} +}; + +struct Quux : Baz, 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()'}}