hazohelet created this revision. hazohelet added reviewers: aaron.ballman, erichkeane, shafik, tbaeder. Herald added a project: All. hazohelet requested review of this revision. Herald added a project: clang.
This patch fixes the reported regression caused by D146358 <https://reviews.llvm.org/D146358> through adding notes about an uninitialized base class when we diagnose uninitialized constructor. This also changes the wording from the old one in order to make it clear that the uninitialized subobject is a base class and its constructor is not called. Wording changes: BEFORE: `subobject of type 'Base' is not initialized` AFTER: `constructor of base class 'Base' is not called` BEFORE: `subobject declared here` AFTER: `base class inherited here` Fixes https://github.com/llvm/llvm-project/issues/63496 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D153969 Files: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticASTKinds.td clang/lib/AST/ExprConstant.cpp clang/test/SemaCXX/constexpr-subobj-initialization.cpp Index: clang/test/SemaCXX/constexpr-subobj-initialization.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/constexpr-subobj-initialization.cpp @@ -0,0 +1,34 @@ +// 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{{base class inherited here}} + 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 '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 'DelBase' is not called}} + +struct Base {}; +struct A : Base { // expected-note {{base class inherited here}} + 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 'Base' is not called}} + +struct B : Base { // expected-note {{base class inherited here}} + 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 'Base' is not called}} +} // namespace baseclass_uninit + 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<CXXRecordDecl>(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()) { + Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized_base) + << BS.getType(); + Info.Note(BS.getBeginLoc(), diag::note_constexpr_base_inherited_here); + return false; + } + if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(), BaseValue, + Kind, /*SubobjectDecl=*/nullptr, + CheckedTemps)) return false; ++BaseIndex; } Index: clang/include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticASTKinds.td +++ clang/include/clang/Basic/DiagnosticASTKinds.td @@ -70,10 +70,14 @@ "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< "subobject declared here">; +def note_constexpr_base_inherited_here : Note< + "base class inherited here">; def note_constexpr_array_index : Note<"cannot refer to element %0 of " "%select{array of %2 element%plural{1:|:s}2|non-array object}1 " "in a constant expression">; Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -375,6 +375,8 @@ by making use of the syntactical structure of function calls. This avoids display of syntactically invalid codes in diagnostics. (`#57081: <https://github.com/llvm/llvm-project/issues/57081>`_) +- Clang contexpr evaluator now displays notes as well as an error when a constructor + of base class is not called in the constructor of its derived class. Bug Fixes in This Version -------------------------
Index: clang/test/SemaCXX/constexpr-subobj-initialization.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/constexpr-subobj-initialization.cpp @@ -0,0 +1,34 @@ +// 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{{base class inherited here}} + 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 '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 'DelBase' is not called}} + +struct Base {}; +struct A : Base { // expected-note {{base class inherited here}} + 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 'Base' is not called}} + +struct B : Base { // expected-note {{base class inherited here}} + 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 'Base' is not called}} +} // namespace baseclass_uninit + 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<CXXRecordDecl>(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()) { + Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized_base) + << BS.getType(); + Info.Note(BS.getBeginLoc(), diag::note_constexpr_base_inherited_here); + return false; + } + if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(), BaseValue, + Kind, /*SubobjectDecl=*/nullptr, + CheckedTemps)) return false; ++BaseIndex; } Index: clang/include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticASTKinds.td +++ clang/include/clang/Basic/DiagnosticASTKinds.td @@ -70,10 +70,14 @@ "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< "subobject declared here">; +def note_constexpr_base_inherited_here : Note< + "base class inherited here">; def note_constexpr_array_index : Note<"cannot refer to element %0 of " "%select{array of %2 element%plural{1:|:s}2|non-array object}1 " "in a constant expression">; Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -375,6 +375,8 @@ by making use of the syntactical structure of function calls. This avoids display of syntactically invalid codes in diagnostics. (`#57081: <https://github.com/llvm/llvm-project/issues/57081>`_) +- Clang contexpr evaluator now displays notes as well as an error when a constructor + of base class is not called in the constructor of its derived class. Bug Fixes in This Version -------------------------
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits