@@ -1609,8 +1609,11 @@ namespace {
16091609 SubobjectDesignator Designator;
16101610 bool IsNullPtr : 1;
16111611 bool InvalidBase : 1;
1612+ // P2280R4 track if we have an unknown reference or pointer.
1613+ bool AllowConstexprUnknown = false;
16121614
16131615 const APValue::LValueBase getLValueBase() const { return Base; }
1616+ bool allowConstexprUnknown() const { return AllowConstexprUnknown; }
16141617 CharUnits &getLValueOffset() { return Offset; }
16151618 const CharUnits &getLValueOffset() const { return Offset; }
16161619 SubobjectDesignator &getLValueDesignator() { return Designator; }
@@ -1628,6 +1631,8 @@ namespace {
16281631 V = APValue(Base, Offset, Designator.Entries,
16291632 Designator.IsOnePastTheEnd, IsNullPtr);
16301633 }
1634+ if (AllowConstexprUnknown)
1635+ V.setConstexprUnknown();
16311636 }
16321637 void setFrom(ASTContext &Ctx, const APValue &V) {
16331638 assert(V.isLValue() && "Setting LValue from a non-LValue?");
@@ -1636,6 +1641,7 @@ namespace {
16361641 InvalidBase = false;
16371642 Designator = SubobjectDesignator(Ctx, V);
16381643 IsNullPtr = V.isNullPointer();
1644+ AllowConstexprUnknown = V.allowConstexprUnknown();
16391645 }
16401646
16411647 void set(APValue::LValueBase B, bool BInvalid = false) {
@@ -1653,6 +1659,7 @@ namespace {
16531659 InvalidBase = BInvalid;
16541660 Designator = SubobjectDesignator(getType(B));
16551661 IsNullPtr = false;
1662+ AllowConstexprUnknown = false;
16561663 }
16571664
16581665 void setNull(ASTContext &Ctx, QualType PointerTy) {
@@ -1662,6 +1669,7 @@ namespace {
16621669 InvalidBase = false;
16631670 Designator = SubobjectDesignator(PointerTy->getPointeeType());
16641671 IsNullPtr = true;
1672+ AllowConstexprUnknown = false;
16651673 }
16661674
16671675 void setInvalid(APValue::LValueBase B, unsigned I = 0) {
@@ -3300,6 +3308,11 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
33003308static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
33013309 const VarDecl *VD, CallStackFrame *Frame,
33023310 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+
33033316 APValue::LValueBase Base(VD, Frame ? Frame->Index : 0, Version);
33043317
33053318 // If this is a local variable, dig out its value.
@@ -3334,7 +3347,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
33343347 return true;
33353348 }
33363349
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) {
33383353 // Assume parameters of a potential constant expression are usable in
33393354 // constant expressions.
33403355 if (!Info.checkingPotentialConstantExpression() ||
@@ -3358,7 +3373,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
33583373 // FIXME: We should eventually check whether the variable has a reachable
33593374 // initializing declaration.
33603375 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) {
33623379 // Don't diagnose during potential constant expression checking; an
33633380 // initializer might be added later.
33643381 if (!Info.checkingPotentialConstantExpression()) {
@@ -3369,7 +3386,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
33693386 return false;
33703387 }
33713388
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()) {
33733392 // The DeclRefExpr is not value-dependent, but the variable it refers to
33743393 // has a value-dependent initializer. This should only happen in
33753394 // constant-folding cases, where the variable is not actually of a suitable
@@ -3388,7 +3407,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
33883407
33893408 // Check that we can fold the initializer. In C++, we will have already done
33903409 // 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()) {
33923413 Info.FFDiag(E, diag::note_constexpr_var_init_non_constant, 1) << VD;
33933414 NoteLValueLocation(Info, Base);
33943415 return false;
@@ -3420,6 +3441,15 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
34203441 }
34213442
34223443 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+ }
34233453 return true;
34243454}
34253455
@@ -3700,6 +3730,11 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
37003730 const FieldDecl *LastField = nullptr;
37013731 const FieldDecl *VolatileField = nullptr;
37023732
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+
37033738 // Walk the designator's path to find the subobject.
37043739 for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
37053740 // Reading an indeterminate value is undefined, but assigning over one is OK.
@@ -5732,6 +5767,12 @@ struct CheckDynamicTypeHandler {
57325767/// dynamic type.
57335768static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This,
57345769 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+
57355776 if (This.Designator.Invalid)
57365777 return false;
57375778
@@ -5804,7 +5845,13 @@ static std::optional<DynamicType> ComputeDynamicType(EvalInfo &Info,
58045845 // If we don't have an lvalue denoting an object of class type, there is no
58055846 // meaningful dynamic type. (We consider objects of non-class type to have no
58065847 // 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)
58085855 return std::nullopt;
58095856
58105857 // 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,
85398586 const ParmVarDecl *Self = MD->getParamDecl(0);
85408587 if (Self->getType()->isReferenceType()) {
85418588 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);
85438591 } else {
85448592 const ParmVarDecl *VD = Info.CurrentCall->Arguments.getOrigParam(Self);
85458593 CallStackFrame *Frame =
@@ -8595,7 +8643,10 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
85958643
85968644
85978645bool 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();
85998650 // If we are within a lambda's call operator, check whether the 'VD' referred
86008651 // to within 'E' actually represents a lambda-capture that maps to a
86018652 // 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) {
86658716 if (!V->hasValue()) {
86668717 // FIXME: Is it possible for V to be indeterminate here? If so, we should
86678718 // 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)
86698722 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+ }
86708733 return false;
86718734 }
8735+
86728736 return Success(*V, E);
86738737}
86748738
@@ -11486,7 +11550,10 @@ class IntExprEvaluator
1148611550 }
1148711551
1148811552 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()) {
1149011557 Result = V;
1149111558 return true;
1149211559 }
0 commit comments