Skip to content

Commit 5a3c5f0

Browse files
committed
Apply feedback, check constructors and aggregates
1 parent 39b9a09 commit 5a3c5f0

File tree

4 files changed

+90
-34
lines changed

4 files changed

+90
-34
lines changed

clang/include/clang/Basic/DiagnosticASTKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ def access_kind
178178
: TextSubstitution<
179179
"%select{read of|read of|assignment to|increment of|decrement of|"
180180
"member call on|dynamic_cast of|typeid applied to|construction of|"
181-
"destruction of|read of|read of}0">;
181+
"destruction of|read of|binding a reference to}0">;
182182
def access_kind_subobject : TextSubstitution<
183183
"%select{read of|read of|assignment to|increment of|decrement of|"
184184
"member call on|dynamic_cast of|typeid applied to|"

clang/lib/AST/ByteCode/State.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ enum AccessKinds {
3535
AK_Construct,
3636
AK_Destroy,
3737
AK_IsWithinLifetime,
38-
AK_CheckReferenceInitialization
38+
AK_ReferenceInitialization
3939
};
4040

4141
/// The order of this enum is important for diagnostics.

clang/lib/AST/ExprConstant.cpp

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,7 +1529,7 @@ CallStackFrame::~CallStackFrame() {
15291529

15301530
static bool isRead(AccessKinds AK) {
15311531
return AK == AK_Read || AK == AK_ReadObjectRepresentation ||
1532-
AK == AK_IsWithinLifetime || AK == AK_CheckReferenceInitialization;
1532+
AK == AK_IsWithinLifetime || AK == AK_ReferenceInitialization;
15331533
}
15341534

15351535
static bool isModification(AccessKinds AK) {
@@ -1540,7 +1540,7 @@ static bool isModification(AccessKinds AK) {
15401540
case AK_DynamicCast:
15411541
case AK_TypeId:
15421542
case AK_IsWithinLifetime:
1543-
case AK_CheckReferenceInitialization:
1543+
case AK_ReferenceInitialization:
15441544
return false;
15451545
case AK_Assign:
15461546
case AK_Increment:
@@ -1559,7 +1559,7 @@ static bool isAnyAccess(AccessKinds AK) {
15591559
/// Is this an access per the C++ definition?
15601560
static bool isFormalAccess(AccessKinds AK) {
15611561
return isAnyAccess(AK) && AK != AK_Construct && AK != AK_Destroy &&
1562-
AK != AK_IsWithinLifetime && AK != AK_CheckReferenceInitialization;
1562+
AK != AK_IsWithinLifetime && AK != AK_ReferenceInitialization;
15631563
}
15641564

15651565
/// Is this kind of axcess valid on an indeterminate object value?
@@ -1572,7 +1572,7 @@ static bool isValidIndeterminateAccess(AccessKinds AK) {
15721572
return false;
15731573

15741574
case AK_IsWithinLifetime:
1575-
case AK_CheckReferenceInitialization:
1575+
case AK_ReferenceInitialization:
15761576
case AK_ReadObjectRepresentation:
15771577
case AK_Assign:
15781578
case AK_Construct:
@@ -4419,6 +4419,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
44194419
return CompleteObject();
44204420
}
44214421

4422+
// if(AK == clang::AK_ReferenceInitialization)
4423+
// return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
4424+
44224425
bool IsConstant = BaseType.isConstant(Info.Ctx);
44234426
bool ConstexprVar = false;
44244427
if (const auto *VD = dyn_cast_if_present<VarDecl>(
@@ -4427,7 +4430,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
44274430

44284431
// Unless we're looking at a local variable or argument in a constexpr call,
44294432
// the variable we're reading must be const.
4430-
if (!Frame && AK != clang::AK_CheckReferenceInitialization) {
4433+
if (AK != clang::AK_ReferenceInitialization && !Frame) {
44314434
if (IsAccess && isa<ParmVarDecl>(VD)) {
44324435
// Access of a parameter that's not associated with a frame isn't going
44334436
// to work out, but we can leave it to evaluateVarDeclInit to provide a
@@ -4491,7 +4494,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
44914494
}
44924495
}
44934496

4494-
if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
4497+
if (AK != clang::AK_ReferenceInitialization &&
4498+
!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(),
4499+
BaseVal))
44954500
return CompleteObject();
44964501
} else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
44974502
std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
@@ -4504,7 +4509,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
45044509
} else {
45054510
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
45064511

4507-
if (!Frame && AK != clang::AK_CheckReferenceInitialization) {
4512+
if (AK != clang::AK_ReferenceInitialization && !Frame) {
45084513
if (const MaterializeTemporaryExpr *MTE =
45094514
dyn_cast_or_null<MaterializeTemporaryExpr>(Base)) {
45104515
assert(MTE->getStorageDuration() == SD_Static &&
@@ -4558,7 +4563,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
45584563
NoteLValueLocation(Info, LVal.Base);
45594564
return CompleteObject();
45604565
}
4561-
} else if (AK != clang::AK_CheckReferenceInitialization) {
4566+
} else if (AK != clang::AK_ReferenceInitialization) {
45624567
BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion());
45634568
assert(BaseVal && "missing value for temporary");
45644569
}
@@ -5224,6 +5229,24 @@ enum EvalStmtResult {
52245229
};
52255230
}
52265231

5232+
static bool EvaluateInitForDeclOfReferenceType(EvalInfo &Info,
5233+
const ValueDecl *D,
5234+
const Expr *Init, LValue &Result,
5235+
APValue &Val) {
5236+
assert(Init->isGLValue() && D->getType()->isReferenceType());
5237+
if (!EvaluateLValue(Init, Result, Info))
5238+
return false;
5239+
CompleteObject Obj = findCompleteObject(
5240+
Info, Init, AK_ReferenceInitialization, Result, Init->getType());
5241+
if (!Result.Designator.Invalid && Result.Designator.isOnePastTheEnd()) {
5242+
Info.FFDiag(Init, diag::note_constexpr_access_past_end)
5243+
<< AK_ReferenceInitialization;
5244+
return false;
5245+
}
5246+
Result.moveInto(Val);
5247+
return !!Obj;
5248+
}
5249+
52275250
static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
52285251
if (VD->isInvalidDecl())
52295252
return false;
@@ -5244,18 +5267,8 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
52445267
if (InitE->isValueDependent())
52455268
return false;
52465269

5247-
if (VD->getType()->isReferenceType() && InitE->isGLValue()) {
5248-
if (!EvaluateLValue(InitE, Result, Info))
5249-
return false;
5250-
CompleteObject Obj = findCompleteObject(
5251-
Info, InitE, AK_CheckReferenceInitialization, Result, InitE->getType());
5252-
if (Result.Designator.isOnePastTheEnd()) {
5253-
Info.FFDiag(InitE, diag::note_constexpr_access_past_end)
5254-
<< AK_CheckReferenceInitialization;
5255-
return false;
5256-
}
5257-
Result.moveInto(Val);
5258-
return !!Obj;
5270+
if (VD->getType()->isReferenceType()) {
5271+
return EvaluateInitForDeclOfReferenceType(Info, VD, InitE, Result, Val);
52595272
} else if (!EvaluateInPlace(Val, Info, Result, InitE)) {
52605273
// Wipe out any partially-computed value, to allow tracking that this
52615274
// evaluation failed.
@@ -6897,9 +6910,18 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
68976910
ThisOverrideRAII ThisOverride(*Info.CurrentCall, &SubobjectParent,
68986911
isa<CXXDefaultInitExpr>(Init));
68996912
FullExpressionRAII InitScope(Info);
6900-
if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
6901-
(FD && FD->isBitField() &&
6902-
!truncateBitfieldValue(Info, Init, *Value, FD))) {
6913+
6914+
if (FD && FD->getType()->isReferenceType()) {
6915+
LValue Result;
6916+
if (!EvaluateInitForDeclOfReferenceType(Info, FD, Init, Result,
6917+
*Value)) {
6918+
if (!Info.noteFailure())
6919+
return false;
6920+
Success = false;
6921+
}
6922+
} else if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
6923+
(FD && FD->isBitField() &&
6924+
!truncateBitfieldValue(Info, Init, *Value, FD))) {
69036925
// If we're checking for a potential constant expression, evaluate all
69046926
// initializers even if some of them fail.
69056927
if (!Info.noteFailure())
@@ -10926,9 +10948,18 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
1092610948
isa<CXXDefaultInitExpr>(Init));
1092710949

1092810950
APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
10929-
if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
10930-
(Field->isBitField() && !truncateBitfieldValue(Info, Init,
10931-
FieldVal, Field))) {
10951+
10952+
if (Field->getType()->isReferenceType()) {
10953+
LValue Result;
10954+
if (!EvaluateInitForDeclOfReferenceType(Info, Field, Init, Result,
10955+
FieldVal)) {
10956+
if (!Info.noteFailure())
10957+
return false;
10958+
Success = false;
10959+
}
10960+
} else if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
10961+
(Field->isBitField() &&
10962+
!truncateBitfieldValue(Info, Init, FieldVal, Field))) {
1093210963
if (!Info.noteFailure())
1093310964
return false;
1093410965
Success = false;

clang/test/SemaCXX/constant-expression-cxx14.cpp

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ namespace subobject {
250250
namespace lifetime {
251251
constexpr int &&id(int &&n) { return static_cast<int&&>(n); }
252252
constexpr int &&dead() { return id(0); } // expected-note {{temporary created here}}
253-
constexpr int bad() { int &&n = dead(); n = 1; return n; } // expected-note {{read of temporary whose lifetime has ended}}
253+
constexpr int bad() { int &&n = dead(); n = 1; return n; } // expected-note {{binding a reference to temporary whose lifetime has ended}}
254254
static_assert(bad(), ""); // expected-error {{constant expression}} expected-note {{in call}}
255255
}
256256

@@ -1325,20 +1325,45 @@ constexpr bool check = different_in_loop();
13251325
namespace GH48665 {
13261326
constexpr bool foo(int *i) {
13271327
int &j = *i;
1328-
// expected-note@-1 {{read of dereferenced null pointer is not allowed in a constant expression}}
1328+
// expected-note@-1 {{binding a reference to dereferenced null pointer is not allowed in a constant expression}}
13291329
return true;
13301330
}
13311331

13321332
static_assert(foo(nullptr), ""); // expected-note {{in call to 'foo(nullptr)'}}
13331333
// expected-error@-1 {{static assertion expression is not an integral constant expression}}
13341334

1335-
int arr[3]; // expected-note 2{{declared here}}
1335+
int arr[3]; // expected-note {{declared here}}
13361336
constexpr bool f() { // cxx14_20-error {{constexpr function never produces a constant expression}}
1337-
int &r = arr[3]; // cxx14_20-note {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}} \
1338-
// expected-warning {{array index 3 is past the end of the array}}\
1339-
// expected-note {{initializer of 'arr' is unknown}}
1337+
int &r = arr[3]; // cxx14_20-note {{binding a reference to dereferenced one-past-the-end pointer is not allowed in a constant expression}} \
1338+
// expected-note {{binding a reference to dereferenced one-past-the-end pointer is not allowed in a constant expression}} \
1339+
// expected-warning {{array index 3 is past the end of the array}}
13401340
return true;
13411341
}
13421342
static_assert(f(), ""); // expected-note {{in call to 'f()'}}
13431343
// expected-error@-1 {{static assertion expression is not an integral constant expression}}
1344+
1345+
1346+
struct Aggregate {
1347+
int &r;
1348+
};
1349+
constexpr bool test_agg(int *i) {
1350+
Aggregate a{*i}; //expected-note {{binding a reference to dereferenced null pointer is not allowed in a constant expression}}
1351+
return true;
1352+
}
1353+
static_assert(test_agg(nullptr), ""); // expected-note {{in call to 'test_agg(nullptr)'}}
1354+
// expected-error@-1 {{static assertion expression is not an integral constant expression}}
1355+
1356+
struct B {
1357+
constexpr B(int *p) : r{*p} {} // expected-note {{binding a reference to dereferenced null pointer is not allowed in a constant expression}}
1358+
int &r;
1359+
};
1360+
1361+
constexpr bool test_ctr(int *i) {
1362+
B b(i); // expected-note {{in call to 'B(nullptr)'}}
1363+
return true;
1364+
}
1365+
1366+
static_assert(test_ctr(nullptr), ""); // expected-note {{in call to 'test_ctr(nullptr)'}}
1367+
// expected-error@-1 {{static assertion expression is not an integral constant expression}}
1368+
13441369
}

0 commit comments

Comments
 (0)