@@ -1609,8 +1609,11 @@ namespace {
1609
1609
SubobjectDesignator Designator;
1610
1610
bool IsNullPtr : 1;
1611
1611
bool InvalidBase : 1;
1612
+ // P2280R4 track if we have an unknown reference or pointer.
1613
+ bool AllowConstexprUnknown = false;
1612
1614
1613
1615
const APValue::LValueBase getLValueBase() const { return Base; }
1616
+ bool allowConstexprUnknown() const { return AllowConstexprUnknown; }
1614
1617
CharUnits &getLValueOffset() { return Offset; }
1615
1618
const CharUnits &getLValueOffset() const { return Offset; }
1616
1619
SubobjectDesignator &getLValueDesignator() { return Designator; }
@@ -1628,6 +1631,8 @@ namespace {
1628
1631
V = APValue(Base, Offset, Designator.Entries,
1629
1632
Designator.IsOnePastTheEnd, IsNullPtr);
1630
1633
}
1634
+ if (AllowConstexprUnknown)
1635
+ V.setConstexprUnknown();
1631
1636
}
1632
1637
void setFrom(ASTContext &Ctx, const APValue &V) {
1633
1638
assert(V.isLValue() && "Setting LValue from a non-LValue?");
@@ -1636,6 +1641,7 @@ namespace {
1636
1641
InvalidBase = false;
1637
1642
Designator = SubobjectDesignator(Ctx, V);
1638
1643
IsNullPtr = V.isNullPointer();
1644
+ AllowConstexprUnknown = V.allowConstexprUnknown();
1639
1645
}
1640
1646
1641
1647
void set(APValue::LValueBase B, bool BInvalid = false) {
@@ -1653,6 +1659,7 @@ namespace {
1653
1659
InvalidBase = BInvalid;
1654
1660
Designator = SubobjectDesignator(getType(B));
1655
1661
IsNullPtr = false;
1662
+ AllowConstexprUnknown = false;
1656
1663
}
1657
1664
1658
1665
void setNull(ASTContext &Ctx, QualType PointerTy) {
@@ -1662,6 +1669,7 @@ namespace {
1662
1669
InvalidBase = false;
1663
1670
Designator = SubobjectDesignator(PointerTy->getPointeeType());
1664
1671
IsNullPtr = true;
1672
+ AllowConstexprUnknown = false;
1665
1673
}
1666
1674
1667
1675
void setInvalid(APValue::LValueBase B, unsigned I = 0) {
@@ -3300,6 +3308,11 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
3300
3308
static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3301
3309
const VarDecl *VD, CallStackFrame *Frame,
3302
3310
unsigned Version, APValue *&Result) {
3311
+ // P2280R4 If we have a reference type and we are in C++23 allow unknown
3312
+ // references and pointers.
3313
+ bool AllowConstexprUnknown =
3314
+ Info.getLangOpts().CPlusPlus23 && VD->getType()->isReferenceType();
3315
+
3303
3316
APValue::LValueBase Base(VD, Frame ? Frame->Index : 0, Version);
3304
3317
3305
3318
// If this is a local variable, dig out its value.
@@ -3334,7 +3347,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3334
3347
return true;
3335
3348
}
3336
3349
3337
- if (isa<ParmVarDecl>(VD)) {
3350
+ // P2280R4 struck the restriction that variable of referene type lifetime
3351
+ // should begin within the evaluation of E
3352
+ if (isa<ParmVarDecl>(VD) && !AllowConstexprUnknown) {
3338
3353
// Assume parameters of a potential constant expression are usable in
3339
3354
// constant expressions.
3340
3355
if (!Info.checkingPotentialConstantExpression() ||
@@ -3358,7 +3373,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3358
3373
// FIXME: We should eventually check whether the variable has a reachable
3359
3374
// initializing declaration.
3360
3375
const Expr *Init = VD->getAnyInitializer(VD);
3361
- if (!Init) {
3376
+ // P2280R4 struck the restriction that variable of referene type should have
3377
+ // a preceding initialization.
3378
+ if (!Init && !AllowConstexprUnknown) {
3362
3379
// Don't diagnose during potential constant expression checking; an
3363
3380
// initializer might be added later.
3364
3381
if (!Info.checkingPotentialConstantExpression()) {
@@ -3369,7 +3386,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3369
3386
return false;
3370
3387
}
3371
3388
3372
- if (Init->isValueDependent()) {
3389
+ // P2280R4 struck the initialization requirement for variables of reference
3390
+ // type so we can no longer assume we have an Init.
3391
+ if (Init && Init->isValueDependent()) {
3373
3392
// The DeclRefExpr is not value-dependent, but the variable it refers to
3374
3393
// has a value-dependent initializer. This should only happen in
3375
3394
// constant-folding cases, where the variable is not actually of a suitable
@@ -3388,7 +3407,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3388
3407
3389
3408
// Check that we can fold the initializer. In C++, we will have already done
3390
3409
// this in the cases where it matters for conformance.
3391
- if (!VD->evaluateValue()) {
3410
+ // P2280R4 struck the initialization requirement for variables of reference
3411
+ // type so we can no longer assume we have an Init.
3412
+ if (Init && !VD->evaluateValue()) {
3392
3413
Info.FFDiag(E, diag::note_constexpr_var_init_non_constant, 1) << VD;
3393
3414
NoteLValueLocation(Info, Base);
3394
3415
return false;
@@ -3420,6 +3441,15 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3420
3441
}
3421
3442
3422
3443
Result = VD->getEvaluatedValue();
3444
+
3445
+ // P2280R4 If we don't have a value because this is a reference that was not
3446
+ // initialized or whose lifetime began within E then create a value with as
3447
+ // a ConstexprUnknown status.
3448
+ if (AllowConstexprUnknown) {
3449
+ if (!Result) {
3450
+ Result = new APValue(Base, APValue::ConstexprUnknown{}, CharUnits::One());
3451
+ }
3452
+ }
3423
3453
return true;
3424
3454
}
3425
3455
@@ -3700,6 +3730,11 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
3700
3730
const FieldDecl *LastField = nullptr;
3701
3731
const FieldDecl *VolatileField = nullptr;
3702
3732
3733
+ // P2280R4 If we have an unknown referene or pointer and we don't have a
3734
+ // value then bail out.
3735
+ if (O->allowConstexprUnknown() && !O->hasValue())
3736
+ return false;
3737
+
3703
3738
// Walk the designator's path to find the subobject.
3704
3739
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
3705
3740
// Reading an indeterminate value is undefined, but assigning over one is OK.
@@ -5732,6 +5767,12 @@ struct CheckDynamicTypeHandler {
5732
5767
/// dynamic type.
5733
5768
static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This,
5734
5769
AccessKinds AK, bool Polymorphic) {
5770
+ // P2280R4 We are not allowed to invoke a virtual function whose dynamic type
5771
+ // us constexpr-unknown, so stop early and let this fail later on if we
5772
+ // attempt to do so.
5773
+ if (This.allowConstexprUnknown())
5774
+ return true;
5775
+
5735
5776
if (This.Designator.Invalid)
5736
5777
return false;
5737
5778
@@ -5804,7 +5845,13 @@ static std::optional<DynamicType> ComputeDynamicType(EvalInfo &Info,
5804
5845
// If we don't have an lvalue denoting an object of class type, there is no
5805
5846
// meaningful dynamic type. (We consider objects of non-class type to have no
5806
5847
// dynamic type.)
5807
- if (!checkDynamicType(Info, E, This, AK, true))
5848
+ if (!checkDynamicType(Info, E, This, AK,
5849
+ (AK == AK_TypeId
5850
+ ? (E->getType()->isReferenceType() ? true : false)
5851
+ : true)))
5852
+ return std::nullopt;
5853
+
5854
+ if (This.Designator.Invalid)
5808
5855
return std::nullopt;
5809
5856
5810
5857
// Refuse to compute a dynamic type in the presence of virtual bases. This
@@ -8539,7 +8586,8 @@ static bool HandleLambdaCapture(EvalInfo &Info, const Expr *E, LValue &Result,
8539
8586
const ParmVarDecl *Self = MD->getParamDecl(0);
8540
8587
if (Self->getType()->isReferenceType()) {
8541
8588
APValue *RefValue = Info.getParamSlot(Info.CurrentCall->Arguments, Self);
8542
- Result.setFrom(Info.Ctx, *RefValue);
8589
+ if (!RefValue->allowConstexprUnknown() || RefValue->hasValue())
8590
+ Result.setFrom(Info.Ctx, *RefValue);
8543
8591
} else {
8544
8592
const ParmVarDecl *VD = Info.CurrentCall->Arguments.getOrigParam(Self);
8545
8593
CallStackFrame *Frame =
@@ -8595,7 +8643,10 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
8595
8643
8596
8644
8597
8645
bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
8598
-
8646
+ // P2280R4 if we are in C++23 track if we have an unknown reference or
8647
+ // pointer.
8648
+ bool AllowConstexprUnknown =
8649
+ Info.getLangOpts().CPlusPlus23 && VD->getType()->isReferenceType();
8599
8650
// If we are within a lambda's call operator, check whether the 'VD' referred
8600
8651
// to within 'E' actually represents a lambda-capture that maps to a
8601
8652
// data-member/field within the closure object, and if so, evaluate to the
@@ -8665,10 +8716,23 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
8665
8716
if (!V->hasValue()) {
8666
8717
// FIXME: Is it possible for V to be indeterminate here? If so, we should
8667
8718
// adjust the diagnostic to say that.
8668
- if (!Info.checkingPotentialConstantExpression())
8719
+ // P2280R4 If we are have a variable that is unknown reference or pointer
8720
+ // it may not have a value but still be usable later on so do not diagnose.
8721
+ if (!Info.checkingPotentialConstantExpression() && !AllowConstexprUnknown)
8669
8722
Info.FFDiag(E, diag::note_constexpr_use_uninit_reference);
8723
+
8724
+ // P2280R4 If we are have a variable that is unknown reference or pointer
8725
+ // try to recover it from the frame and set the result accordingly.
8726
+ if (VD->getType()->isReferenceType() && AllowConstexprUnknown) {
8727
+ if (Frame) {
8728
+ Result.set({VD, Frame->Index, Version});
8729
+ return true;
8730
+ }
8731
+ return Success(VD);
8732
+ }
8670
8733
return false;
8671
8734
}
8735
+
8672
8736
return Success(*V, E);
8673
8737
}
8674
8738
@@ -11486,7 +11550,10 @@ class IntExprEvaluator
11486
11550
}
11487
11551
11488
11552
bool Success(const APValue &V, const Expr *E) {
11489
- if (V.isLValue() || V.isAddrLabelDiff() || V.isIndeterminate()) {
11553
+ // P2280R4 if we have an unknown reference or pointer allow further
11554
+ // evaluation of the value.
11555
+ if (V.isLValue() || V.isAddrLabelDiff() || V.isIndeterminate() ||
11556
+ V.allowConstexprUnknown()) {
11490
11557
Result = V;
11491
11558
return true;
11492
11559
}
0 commit comments