Skip to content

Commit

Permalink
[Clang][Interp] Diagnose uninitialized ctor of global record arrays
Browse files Browse the repository at this point in the history
This patch adds a check for uninitialized subobjects of global variables that are record arrays.
e.g. `constexpr Foo f[2];`

Reviewed By: tbaeder

Differential Revision: https://reviews.llvm.org/D152548
  • Loading branch information
hazohelet committed Jun 21, 2023
1 parent 9119325 commit dfb85c3
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 5 deletions.
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
if (!visitInitializer(Init))
return false;

if (Init->getType()->isRecordType() && !this->emitCheckGlobalCtor(Init))
if ((Init->getType()->isArrayType() || Init->getType()->isRecordType()) &&
!this->emitCheckGlobalCtor(Init))
return false;

return this->emitPopPtr(Init);
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,8 +456,11 @@ static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,

bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) {
assert(!This.isZero());
const Record *R = This.getRecord();
return CheckFieldsInitialized(S, OpPC, This, R);
if (const Record *R = This.getRecord())
return CheckFieldsInitialized(S, OpPC, This, R);
const auto *CAT =
cast<ConstantArrayType>(This.getType()->getAsArrayTypeUnsafe());
return CheckArrayInitialized(S, OpPC, This, CAT);
}

bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status) {
Expand Down
33 changes: 31 additions & 2 deletions clang/test/AST/Interp/cxx20.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,43 @@ static_assert(!b4); // ref-error {{not an integral constant expression}} \
namespace UninitializedFields {
class A {
public:
int a; // expected-note 3{{subobject declared here}} \
// ref-note 3{{subobject declared here}}
int a; // expected-note 4{{subobject declared here}} \
// ref-note 4{{subobject declared here}}
constexpr A() {}
};
constexpr A a; // expected-error {{must be initialized by a constant expression}} \
// expected-note {{subobject 'a' is not initialized}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{subobject 'a' is not initialized}}
constexpr A aarr[2]; // expected-error {{must be initialized by a constant expression}} \
// expected-note {{subobject 'a' is not initialized}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{subobject 'a' is not initialized}}
class F {
public:
int f; // expected-note 3{{subobject declared here}} \
// ref-note 3{{subobject declared here}}

constexpr F() {}
constexpr F(bool b) {
if (b)
f = 42;
}
};

constexpr F foo[2] = {true}; // expected-error {{must be initialized by a constant expression}} \
// expected-note {{subobject 'f' is not initialized}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{subobject 'f' is not initialized}}
constexpr F foo2[3] = {true, false, true}; // expected-error {{must be initialized by a constant expression}} \
// expected-note {{subobject 'f' is not initialized}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{subobject 'f' is not initialized}}
constexpr F foo3[3] = {true, true, F()}; // expected-error {{must be initialized by a constant expression}} \
// expected-note {{subobject 'f' is not initialized}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{subobject 'f' is not initialized}}



class Base {
Expand Down

0 comments on commit dfb85c3

Please sign in to comment.