[PATCH] D153969: [clang][ExprConstant] Fix crash on uninitialized base class subobject

Takuya Shimizu via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 28 06:33:54 PDT 2023


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
 -------------------------


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D153969.535365.patch
Type: text/x-patch
Size: 4438 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20230628/613b9219/attachment.bin>


More information about the cfe-commits mailing list