Skip to content

Commit f58d54a

Browse files
authored
[clang][Interp] Diagnose uninitialized bases (llvm#67131)
1 parent fb0a7c8 commit f58d54a

File tree

6 files changed

+92
-3
lines changed

6 files changed

+92
-3
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
561561
if (!this->visitInitializer(Init))
562562
return false;
563563

564-
if (!this->emitPopPtr(E))
564+
if (!this->emitInitPtrPop(E))
565565
return false;
566566
// Base initializers don't increase InitIndex, since they don't count
567567
// into the Record's fields.
@@ -1718,7 +1718,7 @@ bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R,
17181718
return false;
17191719
if (!this->visitZeroRecordInitializer(B.R, E))
17201720
return false;
1721-
if (!this->emitPopPtr(E))
1721+
if (!this->emitInitPtrPop(E))
17221722
return false;
17231723
}
17241724

clang/lib/AST/Interp/ByteCodeStmtGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
191191
return false;
192192
if (!this->visitInitializer(InitExpr))
193193
return false;
194-
if (!this->emitPopPtr(InitExpr))
194+
if (!this->emitInitPtrPop(InitExpr))
195195
return false;
196196
}
197197
}

clang/lib/AST/Interp/Interp.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,12 @@ static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
467467
// Check Fields in all bases
468468
for (const Record::Base &B : R->bases()) {
469469
Pointer P = BasePtr.atField(B.Offset);
470+
if (!P.isInitialized()) {
471+
S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(),
472+
diag::note_constexpr_uninitialized_base)
473+
<< B.Desc->getType();
474+
return false;
475+
}
470476
Result &= CheckFieldsInitialized(S, OpPC, P, B.R);
471477
}
472478

clang/lib/AST/Interp/Interp.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,12 @@ inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
12451245
return true;
12461246
}
12471247

1248+
inline bool InitPtrPop(InterpState &S, CodePtr OpPC) {
1249+
const Pointer &Ptr = S.Stk.pop<Pointer>();
1250+
Ptr.initialize();
1251+
return true;
1252+
}
1253+
12481254
inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
12491255
const Pointer &Ptr) {
12501256
Pointer Base = Ptr;

clang/lib/AST/Interp/Opcodes.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,10 @@ def GetPtrBasePop : Opcode {
304304
let Args = [ArgUint32];
305305
}
306306

307+
def InitPtrPop : Opcode {
308+
let Args = [];
309+
}
310+
307311
def GetPtrDerivedPop : Opcode {
308312
let Args = [ArgUint32];
309313
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter
2+
3+
/// This is like the version in test/SemaCXX/, but some of the
4+
/// output types and their location has been adapted.
5+
/// Differences:
6+
/// 1) The type of the uninitialized base class is printed WITH the namespace,
7+
/// i.e. 'baseclass_uninit::DelBase' instead of just 'DelBase'.
8+
/// 2) The location is not the base specifier declaration, but the call site
9+
/// of the constructor.
10+
11+
12+
namespace baseclass_uninit {
13+
struct DelBase {
14+
constexpr DelBase() = delete; // expected-note {{'DelBase' has been explicitly marked deleted here}}
15+
};
16+
17+
struct Foo : DelBase {
18+
constexpr Foo() {}; // expected-error {{call to deleted constructor of 'DelBase'}}
19+
};
20+
constexpr Foo f; // expected-error {{must be initialized by a constant expression}} \
21+
// expected-note {{constructor of base class 'baseclass_uninit::DelBase' is not called}}
22+
23+
struct Bar : Foo {
24+
constexpr Bar() {};
25+
};
26+
constexpr Bar bar; // expected-error {{must be initialized by a constant expression}} \
27+
// expected-note {{constructor of base class 'baseclass_uninit::DelBase' is not called}}
28+
29+
struct Base {};
30+
struct A : Base {
31+
constexpr A() : value() {} // expected-error {{member initializer 'value' does not name a non-static data member or base class}}
32+
};
33+
34+
constexpr A a; // expected-error {{must be initialized by a constant expression}} \
35+
// expected-note {{constructor of base class 'baseclass_uninit::Base' is not called}}
36+
37+
38+
struct B : Base {
39+
constexpr B() : {} // expected-error {{expected class member or base class name}}
40+
};
41+
42+
constexpr B b; // expected-error {{must be initialized by a constant expression}} \
43+
// expected-note {{constructor of base class 'baseclass_uninit::Base' is not called}}
44+
} // namespace baseclass_uninit
45+
46+
47+
struct Foo {
48+
constexpr Foo(); // expected-note 2{{declared here}}
49+
};
50+
51+
constexpr Foo ff; // expected-error {{must be initialized by a constant expression}} \
52+
// expected-note {{undefined constructor 'Foo' cannot be used in a constant expression}}
53+
54+
struct Bar : protected Foo {
55+
int i;
56+
constexpr Bar() : i(12) {} // expected-note {{undefined constructor 'Foo' cannot be used in a constant expression}}
57+
};
58+
59+
constexpr Bar bb; // expected-error {{must be initialized by a constant expression}} \
60+
// expected-note {{in call to 'Bar()'}}
61+
62+
template <typename Ty>
63+
struct Baz {
64+
constexpr Baz(); // expected-note {{declared here}}
65+
};
66+
67+
struct Quux : Baz<Foo>, private Bar {
68+
int i;
69+
constexpr Quux() : i(12) {} // expected-note {{undefined constructor 'Baz' cannot be used in a constant expression}}
70+
};
71+
72+
constexpr Quux qx; // expected-error {{must be initialized by a constant expression}} \
73+
// expected-note {{in call to 'Quux()'}}

0 commit comments

Comments
 (0)