@@ -1529,7 +1529,7 @@ CallStackFrame::~CallStackFrame() {
1529
1529
1530
1530
static bool isRead(AccessKinds AK) {
1531
1531
return AK == AK_Read || AK == AK_ReadObjectRepresentation ||
1532
- AK == AK_IsWithinLifetime;
1532
+ AK == AK_IsWithinLifetime || AK == AK_Dereference ;
1533
1533
}
1534
1534
1535
1535
static bool isModification(AccessKinds AK) {
@@ -1540,6 +1540,7 @@ static bool isModification(AccessKinds AK) {
1540
1540
case AK_DynamicCast:
1541
1541
case AK_TypeId:
1542
1542
case AK_IsWithinLifetime:
1543
+ case AK_Dereference:
1543
1544
return false;
1544
1545
case AK_Assign:
1545
1546
case AK_Increment:
@@ -1558,15 +1559,16 @@ static bool isAnyAccess(AccessKinds AK) {
1558
1559
/// Is this an access per the C++ definition?
1559
1560
static bool isFormalAccess(AccessKinds AK) {
1560
1561
return isAnyAccess(AK) && AK != AK_Construct && AK != AK_Destroy &&
1561
- AK != AK_IsWithinLifetime;
1562
+ AK != AK_IsWithinLifetime && AK != AK_Dereference ;
1562
1563
}
1563
1564
1564
- /// Is this kind of axcess valid on an indeterminate object value?
1565
+ /// Is this kind of access valid on an indeterminate object value?
1565
1566
static bool isValidIndeterminateAccess(AccessKinds AK) {
1566
1567
switch (AK) {
1567
1568
case AK_Read:
1568
1569
case AK_Increment:
1569
1570
case AK_Decrement:
1571
+ case AK_Dereference:
1570
1572
// These need the object's value.
1571
1573
return false;
1572
1574
@@ -1733,7 +1735,10 @@ namespace {
1733
1735
bool checkNullPointerForFoldAccess(EvalInfo &Info, const Expr *E,
1734
1736
AccessKinds AK) {
1735
1737
return checkNullPointerDiagnosingWith([&Info, E, AK] {
1736
- Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
1738
+ if (AK == AccessKinds::AK_Dereference)
1739
+ Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
1740
+ else
1741
+ Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
1737
1742
});
1738
1743
}
1739
1744
@@ -4305,7 +4310,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4305
4310
}
4306
4311
4307
4312
if (!LVal.Base) {
4308
- Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
4313
+ if (AK == AccessKinds::AK_Dereference)
4314
+ Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
4315
+ else
4316
+ Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
4309
4317
return CompleteObject();
4310
4318
}
4311
4319
@@ -4407,8 +4415,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4407
4415
ConstexprVar = VD->isConstexpr();
4408
4416
4409
4417
// Unless we're looking at a local variable or argument in a constexpr call,
4410
- // the variable we're reading must be const.
4411
- if (!Frame) {
4418
+ // the variable we're reading must be const (unless we are binding to a
4419
+ // reference).
4420
+ if (AK != clang::AK_Dereference && !Frame) {
4412
4421
if (IsAccess && isa<ParmVarDecl>(VD)) {
4413
4422
// Access of a parameter that's not associated with a frame isn't going
4414
4423
// to work out, but we can leave it to evaluateVarDeclInit to provide a
@@ -4472,12 +4481,16 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4472
4481
}
4473
4482
}
4474
4483
4475
- if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
4484
+ // When binding to a reference, the variable does not need to be constexpr
4485
+ // or have constant initalization.
4486
+ if (AK != clang::AK_Dereference &&
4487
+ !evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(),
4488
+ BaseVal))
4476
4489
return CompleteObject();
4477
4490
// If evaluateVarDeclInit sees a constexpr-unknown variable, it returns
4478
4491
// a null BaseVal. Any constexpr-unknown variable seen here is an error:
4479
4492
// we can't access a constexpr-unknown object.
4480
- if (!BaseVal) {
4493
+ if (AK != clang::AK_Dereference && !BaseVal) {
4481
4494
Info.FFDiag(E, diag::note_constexpr_access_unknown_variable, 1)
4482
4495
<< AK << VD;
4483
4496
Info.Note(VD->getLocation(), diag::note_declared_at);
@@ -4491,7 +4504,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4491
4504
}
4492
4505
return CompleteObject(LVal.Base, &(*Alloc)->Value,
4493
4506
LVal.Base.getDynamicAllocType());
4494
- } else {
4507
+ }
4508
+ // When binding to a reference, the variable does not need to be
4509
+ // within its lifetime.
4510
+ else if (AK != clang::AK_Dereference) {
4495
4511
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
4496
4512
4497
4513
if (!Frame) {
@@ -4572,7 +4588,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4572
4588
NoteLValueLocation(Info, LVal.Base);
4573
4589
return CompleteObject();
4574
4590
}
4575
- } else {
4591
+ } else if (AK != clang::AK_Dereference) {
4576
4592
BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion());
4577
4593
assert(BaseVal && "missing value for temporary");
4578
4594
}
@@ -5200,6 +5216,29 @@ enum EvalStmtResult {
5200
5216
ESR_CaseNotFound
5201
5217
};
5202
5218
}
5219
+ /// Evaluates the initializer of a reference.
5220
+ static bool EvaluateInitForDeclOfReferenceType(EvalInfo &Info,
5221
+ const ValueDecl *D,
5222
+ const Expr *Init, LValue &Result,
5223
+ APValue &Val) {
5224
+ assert(Init->isGLValue() && D->getType()->isReferenceType());
5225
+ // A reference is an lvalue.
5226
+ if (!EvaluateLValue(Init, Result, Info))
5227
+ return false;
5228
+ // [C++26][decl.ref]
5229
+ // The object designated by such a glvalue can be outside its lifetime
5230
+ // Because a null pointer value or a pointer past the end of an object
5231
+ // does not point to an object, a reference in a well-defined program cannot
5232
+ // refer to such things;
5233
+ if (!Result.Designator.Invalid && Result.Designator.isOnePastTheEnd()) {
5234
+ Info.FFDiag(Init, diag::note_constexpr_access_past_end) << AK_Dereference;
5235
+ return false;
5236
+ }
5237
+
5238
+ // Save the result.
5239
+ Result.moveInto(Val);
5240
+ return true;
5241
+ }
5203
5242
5204
5243
static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
5205
5244
if (VD->isInvalidDecl())
@@ -5221,7 +5260,11 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
5221
5260
if (InitE->isValueDependent())
5222
5261
return false;
5223
5262
5224
- if (!EvaluateInPlace(Val, Info, Result, InitE)) {
5263
+ // For references to objects, check they do not designate a one-past-the-end
5264
+ // object.
5265
+ if (VD->getType()->isReferenceType()) {
5266
+ return EvaluateInitForDeclOfReferenceType(Info, VD, InitE, Result, Val);
5267
+ } else if (!EvaluateInPlace(Val, Info, Result, InitE)) {
5225
5268
// Wipe out any partially-computed value, to allow tracking that this
5226
5269
// evaluation failed.
5227
5270
Val = APValue();
@@ -6851,9 +6894,18 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
6851
6894
ThisOverrideRAII ThisOverride(*Info.CurrentCall, &SubobjectParent,
6852
6895
isa<CXXDefaultInitExpr>(Init));
6853
6896
FullExpressionRAII InitScope(Info);
6854
- if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
6855
- (FD && FD->isBitField() &&
6856
- !truncateBitfieldValue(Info, Init, *Value, FD))) {
6897
+ if (FD && FD->getType()->isReferenceType() &&
6898
+ !FD->getType()->isFunctionReferenceType()) {
6899
+ LValue Result;
6900
+ if (!EvaluateInitForDeclOfReferenceType(Info, FD, Init, Result,
6901
+ *Value)) {
6902
+ if (!Info.noteFailure())
6903
+ return false;
6904
+ Success = false;
6905
+ }
6906
+ } else if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
6907
+ (FD && FD->isBitField() &&
6908
+ !truncateBitfieldValue(Info, Init, *Value, FD))) {
6857
6909
// If we're checking for a potential constant expression, evaluate all
6858
6910
// initializers even if some of them fail.
6859
6911
if (!Info.noteFailure())
@@ -9287,7 +9339,13 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
9287
9339
}
9288
9340
9289
9341
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
9290
- return evaluatePointer(E->getSubExpr(), Result);
9342
+ bool Success = evaluatePointer(E->getSubExpr(), Result);
9343
+ // [C++26][expr.unary.op]
9344
+ // If the operand points to an object or function, the result
9345
+ // denotes that object or function; otherwise, the behavior is undefined.
9346
+ return Success &&
9347
+ (!E->getType().getNonReferenceType()->isObjectType() ||
9348
+ findCompleteObject(Info, E, AK_Dereference, Result, E->getType()));
9291
9349
}
9292
9350
9293
9351
bool LValueExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
@@ -10906,9 +10964,17 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
10906
10964
isa<CXXDefaultInitExpr>(Init));
10907
10965
10908
10966
APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
10909
- if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
10910
- (Field->isBitField() && !truncateBitfieldValue(Info, Init,
10911
- FieldVal, Field))) {
10967
+ if (Field->getType()->isReferenceType()) {
10968
+ LValue Result;
10969
+ if (!EvaluateInitForDeclOfReferenceType(Info, Field, Init, Result,
10970
+ FieldVal)) {
10971
+ if (!Info.noteFailure())
10972
+ return false;
10973
+ Success = false;
10974
+ }
10975
+ } else if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
10976
+ (Field->isBitField() &&
10977
+ !truncateBitfieldValue(Info, Init, FieldVal, Field))) {
10912
10978
if (!Info.noteFailure())
10913
10979
return false;
10914
10980
Success = false;
0 commit comments