Skip to content

Commit 9fb7e98

Browse files
committed
[AST] Fix a crash on accessing a class without definition in constexpr function context.
Reviewed By: rsmith Differential Revision: https://reviews.llvm.org/D80981
1 parent b5d3abe commit 9fb7e98

File tree

2 files changed

+66
-40
lines changed

2 files changed

+66
-40
lines changed

clang/lib/AST/ExprConstant.cpp

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4475,37 +4475,48 @@ static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
44754475
}
44764476

44774477
/// Get the value to use for a default-initialized object of type T.
4478-
static APValue getDefaultInitValue(QualType T) {
4478+
/// Return false if it encounters something invalid.
4479+
static bool getDefaultInitValue(QualType T, APValue &Result) {
4480+
bool Success = true;
44794481
if (auto *RD = T->getAsCXXRecordDecl()) {
4480-
if (RD->isUnion())
4481-
return APValue((const FieldDecl*)nullptr);
4482-
4483-
APValue Struct(APValue::UninitStruct(), RD->getNumBases(),
4484-
std::distance(RD->field_begin(), RD->field_end()));
4482+
if (RD->isInvalidDecl()) {
4483+
Result = APValue();
4484+
return false;
4485+
}
4486+
if (RD->isUnion()) {
4487+
Result = APValue((const FieldDecl *)nullptr);
4488+
return true;
4489+
}
4490+
Result = APValue(APValue::UninitStruct(), RD->getNumBases(),
4491+
std::distance(RD->field_begin(), RD->field_end()));
44854492

44864493
unsigned Index = 0;
44874494
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
4488-
End = RD->bases_end(); I != End; ++I, ++Index)
4489-
Struct.getStructBase(Index) = getDefaultInitValue(I->getType());
4495+
End = RD->bases_end();
4496+
I != End; ++I, ++Index)
4497+
Success &= getDefaultInitValue(I->getType(), Result.getStructBase(Index));
44904498

44914499
for (const auto *I : RD->fields()) {
44924500
if (I->isUnnamedBitfield())
44934501
continue;
4494-
Struct.getStructField(I->getFieldIndex()) =
4495-
getDefaultInitValue(I->getType());
4502+
Success &= getDefaultInitValue(I->getType(),
4503+
Result.getStructField(I->getFieldIndex()));
44964504
}
4497-
return Struct;
4505+
return Success;
44984506
}
44994507

45004508
if (auto *AT =
45014509
dyn_cast_or_null<ConstantArrayType>(T->getAsArrayTypeUnsafe())) {
4502-
APValue Array(APValue::UninitArray(), 0, AT->getSize().getZExtValue());
4503-
if (Array.hasArrayFiller())
4504-
Array.getArrayFiller() = getDefaultInitValue(AT->getElementType());
4505-
return Array;
4510+
Result = APValue(APValue::UninitArray(), 0, AT->getSize().getZExtValue());
4511+
if (Result.hasArrayFiller())
4512+
Success &=
4513+
getDefaultInitValue(AT->getElementType(), Result.getArrayFiller());
4514+
4515+
return Success;
45064516
}
45074517

4508-
return APValue::IndeterminateValue();
4518+
Result = APValue::IndeterminateValue();
4519+
return true;
45094520
}
45104521

45114522
namespace {
@@ -4535,10 +4546,8 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
45354546
Info.CurrentCall->createTemporary(VD, VD->getType(), true, Result);
45364547

45374548
const Expr *InitE = VD->getInit();
4538-
if (!InitE) {
4539-
Val = getDefaultInitValue(VD->getType());
4540-
return true;
4541-
}
4549+
if (!InitE)
4550+
return getDefaultInitValue(VD->getType(), Val);
45424551

45434552
if (InitE->isValueDependent())
45444553
return false;
@@ -5535,11 +5544,11 @@ struct StartLifetimeOfUnionMemberHandler {
55355544
const Expr *LHSExpr;
55365545
const FieldDecl *Field;
55375546
bool DuringInit;
5538-
5547+
bool Failed = false;
55395548
static const AccessKinds AccessKind = AK_Assign;
55405549

55415550
typedef bool result_type;
5542-
bool failed() { return false; }
5551+
bool failed() { return Failed; }
55435552
bool found(APValue &Subobj, QualType SubobjType) {
55445553
// We are supposed to perform no initialization but begin the lifetime of
55455554
// the object. We interpret that as meaning to do what default
@@ -5563,8 +5572,9 @@ struct StartLifetimeOfUnionMemberHandler {
55635572
diag::note_constexpr_union_member_change_during_init);
55645573
return false;
55655574
}
5566-
5567-
Subobj.setUnion(Field, getDefaultInitValue(Field->getType()));
5575+
APValue Result;
5576+
Failed = !getDefaultInitValue(Field->getType(), Result);
5577+
Subobj.setUnion(Field, Result);
55685578
return true;
55695579
}
55705580
bool found(APSInt &Value, QualType SubobjType) {
@@ -5880,8 +5890,9 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
58805890
for (; !declaresSameEntity(*FieldIt, FD); ++FieldIt) {
58815891
assert(FieldIt != RD->field_end() && "missing field?");
58825892
if (!FieldIt->isUnnamedBitfield())
5883-
Result.getStructField(FieldIt->getFieldIndex()) =
5884-
getDefaultInitValue(FieldIt->getType());
5893+
Success &= getDefaultInitValue(
5894+
FieldIt->getType(),
5895+
Result.getStructField(FieldIt->getFieldIndex()));
58855896
}
58865897
++FieldIt;
58875898
};
@@ -5933,10 +5944,10 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
59335944
if (CD->isUnion())
59345945
*Value = APValue(FD);
59355946
else
5936-
// FIXME: This immediately starts the lifetime of all members of an
5937-
// anonymous struct. It would be preferable to strictly start member
5938-
// lifetime in initialization order.
5939-
*Value = getDefaultInitValue(Info.Ctx.getRecordType(CD));
5947+
// FIXME: This immediately starts the lifetime of all members of
5948+
// an anonymous struct. It would be preferable to strictly start
5949+
// member lifetime in initialization order.
5950+
Success &= getDefaultInitValue(Info.Ctx.getRecordType(CD), *Value);
59405951
}
59415952
// Store Subobject as its parent before updating it for the last element
59425953
// in the chain.
@@ -5983,8 +5994,9 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
59835994
if (!RD->isUnion()) {
59845995
for (; FieldIt != RD->field_end(); ++FieldIt) {
59855996
if (!FieldIt->isUnnamedBitfield())
5986-
Result.getStructField(FieldIt->getFieldIndex()) =
5987-
getDefaultInitValue(FieldIt->getType());
5997+
Success &= getDefaultInitValue(
5998+
FieldIt->getType(),
5999+
Result.getStructField(FieldIt->getFieldIndex()));
59886000
}
59896001
}
59906002

@@ -9070,8 +9082,8 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
90709082
} else if (Init) {
90719083
if (!EvaluateInPlace(*Val, Info, Result, Init))
90729084
return false;
9073-
} else {
9074-
*Val = getDefaultInitValue(AllocType);
9085+
} else if (!getDefaultInitValue(AllocType, *Val)) {
9086+
return false;
90759087
}
90769088

90779089
// Array new returns a pointer to the first element, not a pointer to the
@@ -9442,8 +9454,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
94429454
if (ZeroInit)
94439455
return ZeroInitialization(E, T);
94449456

9445-
Result = getDefaultInitValue(T);
9446-
return true;
9457+
return getDefaultInitValue(T, Result);
94479458
}
94489459

94499460
const FunctionDecl *Definition = nullptr;
@@ -14209,10 +14220,11 @@ bool VarDecl::evaluateDestruction(
1420914220
// Make a copy of the value for the destructor to mutate, if we know it.
1421014221
// Otherwise, treat the value as default-initialized; if the destructor works
1421114222
// anyway, then the destruction is constant (and must be essentially empty).
14212-
APValue DestroyedValue =
14213-
(getEvaluatedValue() && !getEvaluatedValue()->isAbsent())
14214-
? *getEvaluatedValue()
14215-
: getDefaultInitValue(getType());
14223+
APValue DestroyedValue;
14224+
if (getEvaluatedValue() && !getEvaluatedValue()->isAbsent())
14225+
DestroyedValue = *getEvaluatedValue();
14226+
else if (!getDefaultInitValue(getType(), DestroyedValue))
14227+
return false;
1421614228

1421714229
EvalInfo Info(getASTContext(), EStatus, EvalInfo::EM_ConstantExpression);
1421814230
Info.setEvaluatingDecl(this, DestroyedValue,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %clang_cc1 %s -std=c++20 -fsyntax-only -verify
2+
// RUN: %clang_cc1 %s -std=c++20 -fsyntax-only -verify -fno-recovery-ast
3+
4+
namespace NoCrash {
5+
struct ForwardDecl; // expected-note {{forward declaration of}}
6+
struct Foo { // expected-note 2{{candidate constructor}}
7+
ForwardDecl f; // expected-error {{field has incomplete type}}
8+
};
9+
10+
constexpr Foo getFoo() {
11+
Foo e = 123; // expected-error {{no viable conversion from 'int' to 'NoCrash::Foo'}}
12+
return e;
13+
}
14+
}

0 commit comments

Comments
 (0)