@@ -1574,7 +1574,7 @@ CallStackFrame::~CallStackFrame() {
1574
1574
1575
1575
static bool isRead(AccessKinds AK) {
1576
1576
return AK == AK_Read || AK == AK_ReadObjectRepresentation ||
1577
- AK == AK_IsWithinLifetime;
1577
+ AK == AK_IsWithinLifetime || AK == AK_Dereference ;
1578
1578
}
1579
1579
1580
1580
static bool isModification(AccessKinds AK) {
@@ -1585,6 +1585,7 @@ static bool isModification(AccessKinds AK) {
1585
1585
case AK_DynamicCast:
1586
1586
case AK_TypeId:
1587
1587
case AK_IsWithinLifetime:
1588
+ case AK_Dereference:
1588
1589
return false;
1589
1590
case AK_Assign:
1590
1591
case AK_Increment:
@@ -1603,15 +1604,16 @@ static bool isAnyAccess(AccessKinds AK) {
1603
1604
/// Is this an access per the C++ definition?
1604
1605
static bool isFormalAccess(AccessKinds AK) {
1605
1606
return isAnyAccess(AK) && AK != AK_Construct && AK != AK_Destroy &&
1606
- AK != AK_IsWithinLifetime;
1607
+ AK != AK_IsWithinLifetime && AK != AK_Dereference ;
1607
1608
}
1608
1609
1609
- /// Is this kind of axcess valid on an indeterminate object value?
1610
+ /// Is this kind of access valid on an indeterminate object value?
1610
1611
static bool isValidIndeterminateAccess(AccessKinds AK) {
1611
1612
switch (AK) {
1612
1613
case AK_Read:
1613
1614
case AK_Increment:
1614
1615
case AK_Decrement:
1616
+ case AK_Dereference:
1615
1617
// These need the object's value.
1616
1618
return false;
1617
1619
@@ -1831,7 +1833,10 @@ namespace {
1831
1833
bool checkNullPointerForFoldAccess(EvalInfo &Info, const Expr *E,
1832
1834
AccessKinds AK) {
1833
1835
return checkNullPointerDiagnosingWith([&Info, E, AK] {
1834
- Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
1836
+ if (AK == AccessKinds::AK_Dereference)
1837
+ Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
1838
+ else
1839
+ Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
1835
1840
});
1836
1841
}
1837
1842
@@ -4482,7 +4487,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4482
4487
}
4483
4488
4484
4489
if (!LVal.Base) {
4485
- Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
4490
+ if (AK == AccessKinds::AK_Dereference)
4491
+ Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
4492
+ else
4493
+ Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
4486
4494
return CompleteObject();
4487
4495
}
4488
4496
@@ -4584,8 +4592,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4584
4592
ConstexprVar = VD->isConstexpr();
4585
4593
4586
4594
// Unless we're looking at a local variable or argument in a constexpr call,
4587
- // the variable we're reading must be const.
4588
- if (!Frame) {
4595
+ // the variable we're reading must be const (unless we are binding to a
4596
+ // reference).
4597
+ if (AK != clang::AK_Dereference && !Frame) {
4589
4598
if (IsAccess && isa<ParmVarDecl>(VD)) {
4590
4599
// Access of a parameter that's not associated with a frame isn't going
4591
4600
// to work out, but we can leave it to evaluateVarDeclInit to provide a
@@ -4649,12 +4658,16 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4649
4658
}
4650
4659
}
4651
4660
4652
- if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
4661
+ // When binding to a reference, the variable does not need to be constexpr
4662
+ // or have constant initalization.
4663
+ if (AK != clang::AK_Dereference &&
4664
+ !evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(),
4665
+ BaseVal))
4653
4666
return CompleteObject();
4654
4667
// If evaluateVarDeclInit sees a constexpr-unknown variable, it returns
4655
4668
// a null BaseVal. Any constexpr-unknown variable seen here is an error:
4656
4669
// we can't access a constexpr-unknown object.
4657
- if (!BaseVal) {
4670
+ if (AK != clang::AK_Dereference && !BaseVal) {
4658
4671
Info.FFDiag(E, diag::note_constexpr_access_unknown_variable, 1)
4659
4672
<< AK << VD;
4660
4673
Info.Note(VD->getLocation(), diag::note_declared_at);
@@ -4668,7 +4681,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4668
4681
}
4669
4682
return CompleteObject(LVal.Base, &(*Alloc)->Value,
4670
4683
LVal.Base.getDynamicAllocType());
4671
- } else {
4684
+ }
4685
+ // When binding to a reference, the variable does not need to be
4686
+ // within its lifetime.
4687
+ else if (AK != clang::AK_Dereference) {
4672
4688
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
4673
4689
4674
4690
if (!Frame) {
@@ -4749,7 +4765,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4749
4765
NoteLValueLocation(Info, LVal.Base);
4750
4766
return CompleteObject();
4751
4767
}
4752
- } else {
4768
+ } else if (AK != clang::AK_Dereference) {
4753
4769
BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion());
4754
4770
assert(BaseVal && "missing value for temporary");
4755
4771
}
@@ -5377,6 +5393,29 @@ enum EvalStmtResult {
5377
5393
ESR_CaseNotFound
5378
5394
};
5379
5395
}
5396
+ /// Evaluates the initializer of a reference.
5397
+ static bool EvaluateInitForDeclOfReferenceType(EvalInfo &Info,
5398
+ const ValueDecl *D,
5399
+ const Expr *Init, LValue &Result,
5400
+ APValue &Val) {
5401
+ assert(Init->isGLValue() && D->getType()->isReferenceType());
5402
+ // A reference is an lvalue.
5403
+ if (!EvaluateLValue(Init, Result, Info))
5404
+ return false;
5405
+ // [C++26][decl.ref]
5406
+ // The object designated by such a glvalue can be outside its lifetime
5407
+ // Because a null pointer value or a pointer past the end of an object
5408
+ // does not point to an object, a reference in a well-defined program cannot
5409
+ // refer to such things;
5410
+ if (!Result.Designator.Invalid && Result.Designator.isOnePastTheEnd()) {
5411
+ Info.FFDiag(Init, diag::note_constexpr_access_past_end) << AK_Dereference;
5412
+ return false;
5413
+ }
5414
+
5415
+ // Save the result.
5416
+ Result.moveInto(Val);
5417
+ return true;
5418
+ }
5380
5419
5381
5420
static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
5382
5421
if (VD->isInvalidDecl())
@@ -5398,7 +5437,11 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
5398
5437
if (InitE->isValueDependent())
5399
5438
return false;
5400
5439
5401
- if (!EvaluateInPlace(Val, Info, Result, InitE)) {
5440
+ // For references to objects, check they do not designate a one-past-the-end
5441
+ // object.
5442
+ if (VD->getType()->isReferenceType()) {
5443
+ return EvaluateInitForDeclOfReferenceType(Info, VD, InitE, Result, Val);
5444
+ } else if (!EvaluateInPlace(Val, Info, Result, InitE)) {
5402
5445
// Wipe out any partially-computed value, to allow tracking that this
5403
5446
// evaluation failed.
5404
5447
Val = APValue();
@@ -7028,9 +7071,18 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
7028
7071
ThisOverrideRAII ThisOverride(*Info.CurrentCall, &SubobjectParent,
7029
7072
isa<CXXDefaultInitExpr>(Init));
7030
7073
FullExpressionRAII InitScope(Info);
7031
- if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
7032
- (FD && FD->isBitField() &&
7033
- !truncateBitfieldValue(Info, Init, *Value, FD))) {
7074
+ if (FD && FD->getType()->isReferenceType() &&
7075
+ !FD->getType()->isFunctionReferenceType()) {
7076
+ LValue Result;
7077
+ if (!EvaluateInitForDeclOfReferenceType(Info, FD, Init, Result,
7078
+ *Value)) {
7079
+ if (!Info.noteFailure())
7080
+ return false;
7081
+ Success = false;
7082
+ }
7083
+ } else if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
7084
+ (FD && FD->isBitField() &&
7085
+ !truncateBitfieldValue(Info, Init, *Value, FD))) {
7034
7086
// If we're checking for a potential constant expression, evaluate all
7035
7087
// initializers even if some of them fail.
7036
7088
if (!Info.noteFailure())
@@ -9495,7 +9547,13 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
9495
9547
}
9496
9548
9497
9549
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
9498
- return evaluatePointer(E->getSubExpr(), Result);
9550
+ bool Success = evaluatePointer(E->getSubExpr(), Result);
9551
+ // [C++26][expr.unary.op]
9552
+ // If the operand points to an object or function, the result
9553
+ // denotes that object or function; otherwise, the behavior is undefined.
9554
+ return Success &&
9555
+ (!E->getType().getNonReferenceType()->isObjectType() ||
9556
+ findCompleteObject(Info, E, AK_Dereference, Result, E->getType()));
9499
9557
}
9500
9558
9501
9559
bool LValueExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
@@ -11320,9 +11378,17 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
11320
11378
isa<CXXDefaultInitExpr>(Init));
11321
11379
11322
11380
APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
11323
- if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
11324
- (Field->isBitField() && !truncateBitfieldValue(Info, Init,
11325
- FieldVal, Field))) {
11381
+ if (Field->getType()->isReferenceType()) {
11382
+ LValue Result;
11383
+ if (!EvaluateInitForDeclOfReferenceType(Info, Field, Init, Result,
11384
+ FieldVal)) {
11385
+ if (!Info.noteFailure())
11386
+ return false;
11387
+ Success = false;
11388
+ }
11389
+ } else if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
11390
+ (Field->isBitField() &&
11391
+ !truncateBitfieldValue(Info, Init, FieldVal, Field))) {
11326
11392
if (!Info.noteFailure())
11327
11393
return false;
11328
11394
Success = false;
0 commit comments