Skip to content

Commit 8c5c652

Browse files
hazohelettru
authored andcommitted
[clang][ExprConstant] Fix crash on uninitialized base class subobject
This patch fixes the reported regression caused by 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` Fixes llvm#63496 Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D153969
1 parent d469d5c commit 8c5c652

File tree

5 files changed

+83
-3
lines changed

5 files changed

+83
-3
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,8 @@ Improvements to Clang's diagnostics
472472
- Clang now emits ``-Wconstant-logical-operand`` warning even when constant logical
473473
operand is on left side.
474474
(`#37919 <https://github.com/llvm/llvm-project/issues/37919>`_)
475+
- Clang contexpr evaluator now displays notes as well as an error when a constructor
476+
of a base class is not called in the constructor of its derived class.
475477

476478
Bug Fixes in This Version
477479
-------------------------

clang/include/clang/Basic/DiagnosticASTKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ def note_consteval_address_accessible : Note<
7070
"is not a constant expression">;
7171
def note_constexpr_uninitialized : Note<
7272
"subobject %0 is not initialized">;
73+
def note_constexpr_uninitialized_base : Note<
74+
"constructor of base class %0 is not called">;
7375
def note_constexpr_static_local : Note<
7476
"control flows through the definition of a %select{static|thread_local}0 variable">;
7577
def note_constexpr_subobject_declared_here : Note<

clang/lib/AST/ExprConstant.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2418,9 +2418,16 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
24182418
if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
24192419
unsigned BaseIndex = 0;
24202420
for (const CXXBaseSpecifier &BS : CD->bases()) {
2421-
if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(),
2422-
Value.getStructBase(BaseIndex), Kind,
2423-
/*SubobjectDecl=*/nullptr, CheckedTemps))
2421+
const APValue &BaseValue = Value.getStructBase(BaseIndex);
2422+
if (!BaseValue.hasValue()) {
2423+
SourceLocation TypeBeginLoc = BS.getBaseTypeLoc();
2424+
Info.FFDiag(TypeBeginLoc, diag::note_constexpr_uninitialized_base)
2425+
<< BS.getType() << SourceRange(TypeBeginLoc, BS.getEndLoc());
2426+
return false;
2427+
}
2428+
if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(), BaseValue,
2429+
Kind, /*SubobjectDecl=*/nullptr,
2430+
CheckedTemps))
24242431
return false;
24252432
++BaseIndex;
24262433
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-print-source-range-info %s 2>&1 | FileCheck %s --strict-whitespace
2+
3+
struct DelBase {
4+
constexpr DelBase() = delete;
5+
};
6+
7+
// CHECK: :{[[@LINE+1]]:21-[[@LINE+1]]:28}
8+
struct Foo : public DelBase {
9+
constexpr Foo() {};
10+
};
11+
constexpr Foo f;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
namespace baseclass_uninit {
4+
struct DelBase {
5+
constexpr DelBase() = delete; // expected-note {{'DelBase' has been explicitly marked deleted here}}
6+
};
7+
8+
struct Foo : DelBase { // expected-note 2{{constructor of base class 'DelBase' is not called}}
9+
constexpr Foo() {}; // expected-error {{call to deleted constructor of 'DelBase'}}
10+
};
11+
constexpr Foo f; // expected-error {{must be initialized by a constant expression}}
12+
struct Bar : Foo {
13+
constexpr Bar() {};
14+
};
15+
constexpr Bar bar; // expected-error {{must be initialized by a constant expression}}
16+
17+
struct Base {};
18+
struct A : Base { // expected-note {{constructor of base class 'Base' is not called}}
19+
constexpr A() : value() {} // expected-error {{member initializer 'value' does not name a non-static data member or base class}}
20+
};
21+
22+
constexpr A a; // expected-error {{must be initialized by a constant expression}}
23+
24+
struct B : Base { // expected-note {{constructor of base class 'Base' is not called}}
25+
constexpr B() : {} // expected-error {{expected class member or base class name}}
26+
};
27+
28+
constexpr B b; // expected-error {{must be initialized by a constant expression}}
29+
} // namespace baseclass_uninit
30+
31+
32+
struct Foo {
33+
constexpr Foo(); // expected-note 2{{declared here}}
34+
};
35+
36+
constexpr Foo ff; // expected-error {{must be initialized by a constant expression}} \
37+
// expected-note {{undefined constructor 'Foo' cannot be used in a constant expression}}
38+
39+
struct Bar : protected Foo {
40+
int i;
41+
constexpr Bar() : i(12) {} // expected-note {{undefined constructor 'Foo' cannot be used in a constant expression}}
42+
};
43+
44+
constexpr Bar bb; // expected-error {{must be initialized by a constant expression}} \
45+
// expected-note {{in call to 'Bar()'}}
46+
47+
template <typename Ty>
48+
struct Baz {
49+
constexpr Baz(); // expected-note {{declared here}}
50+
};
51+
52+
struct Quux : Baz<Foo>, private Bar {
53+
int i;
54+
constexpr Quux() : i(12) {} // expected-note {{undefined constructor 'Baz' cannot be used in a constant expression}}
55+
};
56+
57+
constexpr Quux qx; // expected-error {{must be initialized by a constant expression}} \
58+
// expected-note {{in call to 'Quux()'}}

0 commit comments

Comments
 (0)