@@ -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,7 +1559,7 @@ 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
1565
/// Is this kind of axcess valid on an indeterminate object value?
@@ -1571,6 +1572,7 @@ static bool isValidIndeterminateAccess(AccessKinds AK) {
1571
1572
return false;
1572
1573
1573
1574
case AK_IsWithinLifetime:
1575
+ case AK_Dereference:
1574
1576
case AK_ReadObjectRepresentation:
1575
1577
case AK_Assign:
1576
1578
case AK_Construct:
@@ -4424,8 +4426,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4424
4426
ConstexprVar = VD->isConstexpr();
4425
4427
4426
4428
// Unless we're looking at a local variable or argument in a constexpr call,
4427
- // the variable we're reading must be const.
4428
- if (!Frame) {
4429
+ // the variable we're reading must be const (unless we are binding to a
4430
+ // reference).
4431
+ if (AK != clang::AK_Dereference && !Frame) {
4429
4432
if (IsAccess && isa<ParmVarDecl>(VD)) {
4430
4433
// Access of a parameter that's not associated with a frame isn't going
4431
4434
// to work out, but we can leave it to evaluateVarDeclInit to provide a
@@ -4489,7 +4492,11 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4489
4492
}
4490
4493
}
4491
4494
4492
- if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
4495
+ // When binding to a reference, the variable does not need to be constexpr
4496
+ // or have constant initalization.
4497
+ if (AK != clang::AK_Dereference &&
4498
+ !evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(),
4499
+ BaseVal))
4493
4500
return CompleteObject();
4494
4501
} else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
4495
4502
std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
@@ -4499,7 +4506,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4499
4506
}
4500
4507
return CompleteObject(LVal.Base, &(*Alloc)->Value,
4501
4508
LVal.Base.getDynamicAllocType());
4502
- } else {
4509
+ }
4510
+ // When binding to a reference, the variable does not need to be
4511
+ // within its lifetime.
4512
+ else if (AK != clang::AK_Dereference) {
4503
4513
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
4504
4514
4505
4515
if (!Frame) {
@@ -4556,7 +4566,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4556
4566
NoteLValueLocation(Info, LVal.Base);
4557
4567
return CompleteObject();
4558
4568
}
4559
- } else {
4569
+ } else if (AK != clang::AK_Dereference) {
4560
4570
BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion());
4561
4571
assert(BaseVal && "missing value for temporary");
4562
4572
}
@@ -5221,6 +5231,29 @@ enum EvalStmtResult {
5221
5231
ESR_CaseNotFound
5222
5232
};
5223
5233
}
5234
+ /// Evaluates the initializer of a reference.
5235
+ static bool EvaluateInitForDeclOfReferenceType(EvalInfo &Info,
5236
+ const ValueDecl *D,
5237
+ const Expr *Init, LValue &Result,
5238
+ APValue &Val) {
5239
+ assert(Init->isGLValue() && D->getType()->isReferenceType());
5240
+ // A reference is an lvalue
5241
+ if (!EvaluateLValue(Init, Result, Info))
5242
+ return false;
5243
+ // [C++26][decl.ref]
5244
+ // The object designated by such a glvalue can be outside its lifetime
5245
+ // Because a null pointer value or a pointer past the end of an object
5246
+ // does not point to an object, a reference in a well-defined program cannot
5247
+ // refer to such things;
5248
+ if (!Result.Designator.Invalid && Result.Designator.isOnePastTheEnd()) {
5249
+ Info.FFDiag(Init, diag::note_constexpr_access_past_end) << AK_Dereference;
5250
+ return false;
5251
+ }
5252
+
5253
+ // save the result
5254
+ Result.moveInto(Val);
5255
+ return true;
5256
+ }
5224
5257
5225
5258
static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
5226
5259
if (VD->isInvalidDecl())
@@ -5242,7 +5275,10 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
5242
5275
if (InitE->isValueDependent())
5243
5276
return false;
5244
5277
5245
- if (!EvaluateInPlace(Val, Info, Result, InitE)) {
5278
+ if (VD->getType()->isReferenceType() &&
5279
+ !VD->getType()->isFunctionReferenceType()) {
5280
+ return EvaluateInitForDeclOfReferenceType(Info, VD, InitE, Result, Val);
5281
+ } else if (!EvaluateInPlace(Val, Info, Result, InitE)) {
5246
5282
// Wipe out any partially-computed value, to allow tracking that this
5247
5283
// evaluation failed.
5248
5284
Val = APValue();
@@ -6883,9 +6919,18 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
6883
6919
ThisOverrideRAII ThisOverride(*Info.CurrentCall, &SubobjectParent,
6884
6920
isa<CXXDefaultInitExpr>(Init));
6885
6921
FullExpressionRAII InitScope(Info);
6886
- if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
6887
- (FD && FD->isBitField() &&
6888
- !truncateBitfieldValue(Info, Init, *Value, FD))) {
6922
+ if (FD && FD->getType()->isReferenceType() &&
6923
+ !FD->getType()->isFunctionReferenceType()) {
6924
+ LValue Result;
6925
+ if (!EvaluateInitForDeclOfReferenceType(Info, FD, Init, Result,
6926
+ *Value)) {
6927
+ if (!Info.noteFailure())
6928
+ return false;
6929
+ Success = false;
6930
+ }
6931
+ } else if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
6932
+ (FD && FD->isBitField() &&
6933
+ !truncateBitfieldValue(Info, Init, *Value, FD))) {
6889
6934
// If we're checking for a potential constant expression, evaluate all
6890
6935
// initializers even if some of them fail.
6891
6936
if (!Info.noteFailure())
@@ -9293,7 +9338,10 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
9293
9338
}
9294
9339
9295
9340
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
9296
- return evaluatePointer(E->getSubExpr(), Result);
9341
+ bool Success = evaluatePointer(E->getSubExpr(), Result);
9342
+ return Success &&
9343
+ (!E->getType().getNonReferenceType()->isObjectType() ||
9344
+ findCompleteObject(Info, E, AK_Dereference, Result, E->getType()));
9297
9345
}
9298
9346
9299
9347
bool LValueExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
@@ -10912,9 +10960,18 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
10912
10960
isa<CXXDefaultInitExpr>(Init));
10913
10961
10914
10962
APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
10915
- if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
10916
- (Field->isBitField() && !truncateBitfieldValue(Info, Init,
10917
- FieldVal, Field))) {
10963
+ if (Field->getType()->isReferenceType() &&
10964
+ !Field->getType()->isFunctionReferenceType()) {
10965
+ LValue Result;
10966
+ if (!EvaluateInitForDeclOfReferenceType(Info, Field, Init, Result,
10967
+ FieldVal)) {
10968
+ if (!Info.noteFailure())
10969
+ return false;
10970
+ Success = false;
10971
+ }
10972
+ } else if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
10973
+ (Field->isBitField() &&
10974
+ !truncateBitfieldValue(Info, Init, FieldVal, Field))) {
10918
10975
if (!Info.noteFailure())
10919
10976
return false;
10920
10977
Success = false;
0 commit comments