@@ -3492,11 +3492,33 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
34923492
34933493 APValue::LValueBase Base(VD, Frame ? Frame->Index : 0, Version);
34943494
3495+ auto CheckUninitReference = [&](bool IsLocalVariable) {
3496+ if (!Result->hasValue() && VD->getType()->isReferenceType()) {
3497+ // C++23 [expr.const]p8
3498+ // ... For such an object that is not usable in constant expressions, the
3499+ // dynamic type of the object is constexpr-unknown. For such a reference
3500+ // that is not usable in constant expressions, the reference is treated
3501+ // as binding to an unspecified object of the referenced type whose
3502+ // lifetime and that of all subobjects includes the entire constant
3503+ // evaluation and whose dynamic type is constexpr-unknown.
3504+ //
3505+ // Variables that are part of the current evaluation are not
3506+ // constexpr-unknown.
3507+ if (!AllowConstexprUnknown || IsLocalVariable) {
3508+ if (!Info.checkingPotentialConstantExpression())
3509+ Info.FFDiag(E, diag::note_constexpr_use_uninit_reference);
3510+ return false;
3511+ }
3512+ Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base);
3513+ }
3514+ return true;
3515+ };
3516+
34953517 // If this is a local variable, dig out its value.
34963518 if (Frame) {
34973519 Result = Frame->getTemporary(VD, Version);
34983520 if (Result)
3499- return true;
3521+ return CheckUninitReference(/*IsLocalVariable=*/ true) ;
35003522
35013523 if (!isa<ParmVarDecl>(VD)) {
35023524 // Assume variables referenced within a lambda's call operator that were
@@ -3521,7 +3543,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
35213543 // in-flight value.
35223544 if (Info.EvaluatingDecl == Base) {
35233545 Result = Info.EvaluatingDeclValue;
3524- return true ;
3546+ return CheckUninitReference(/*IsLocalVariable=*/false) ;
35253547 }
35263548
35273549 // P2280R4 struck the restriction that variable of reference type lifetime
@@ -3594,11 +3616,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
35943616 // type so we can no longer assume we have an Init.
35953617 // Used to be C++20 [expr.const]p5.12:
35963618 // ... reference has a preceding initialization and either ...
3597- if (Init && !VD->evaluateValue()) {
3598- if (AllowConstexprUnknown) {
3599- Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base);
3600- return true;
3601- }
3619+ if (Init && !VD->evaluateValue() && !AllowConstexprUnknown) {
36023620 Info.FFDiag(E, diag::note_constexpr_var_init_non_constant, 1) << VD;
36033621 NoteLValueLocation(Info, Base);
36043622 return false;
@@ -3636,18 +3654,14 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
36363654
36373655 Result = VD->getEvaluatedValue();
36383656
3639- // C++23 [expr.const]p8
3640- // ... For such an object that is not usable in constant expressions, the
3641- // dynamic type of the object is constexpr-unknown. For such a reference that
3642- // is not usable in constant expressions, the reference is treated as binding
3643- // to an unspecified object of the referenced type whose lifetime and that of
3644- // all subobjects includes the entire constant evaluation and whose dynamic
3645- // type is constexpr-unknown.
3646- if (AllowConstexprUnknown) {
3647- if (!Result)
3657+ if (!Result) {
3658+ if (AllowConstexprUnknown)
36483659 Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base);
3660+ else
3661+ return false;
36493662 }
3650- return true;
3663+
3664+ return CheckUninitReference(/*IsLocalVariable=*/false);
36513665}
36523666
36533667/// Get the base index of the given base class within an APValue representing
@@ -8953,12 +8967,7 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
89538967 return Error(E);
89548968}
89558969
8956-
89578970bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
8958- // C++23 [expr.const]p8 If we have a reference type allow unknown references
8959- // and pointers.
8960- bool AllowConstexprUnknown =
8961- Info.getLangOpts().CPlusPlus23 && VD->getType()->isReferenceType();
89628971 // If we are within a lambda's call operator, check whether the 'VD' referred
89638972 // to within 'E' actually represents a lambda-capture that maps to a
89648973 // data-member/field within the closure object, and if so, evaluate to the
@@ -9025,26 +9034,6 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
90259034 APValue *V;
90269035 if (!evaluateVarDeclInit(Info, E, VD, Frame, Version, V))
90279036 return false;
9028- if (!V->hasValue()) {
9029- // FIXME: Is it possible for V to be indeterminate here? If so, we should
9030- // adjust the diagnostic to say that.
9031- // C++23 [expr.const]p8 If we have a variable that is unknown reference
9032- // or pointer it may not have a value but still be usable later on so do not
9033- // diagnose.
9034- if (!Info.checkingPotentialConstantExpression() && !AllowConstexprUnknown)
9035- Info.FFDiag(E, diag::note_constexpr_use_uninit_reference);
9036-
9037- // C++23 [expr.const]p8 If we have a variable that is unknown reference or
9038- // pointer try to recover it from the frame and set the result accordingly.
9039- if (VD->getType()->isReferenceType() && AllowConstexprUnknown) {
9040- if (Frame) {
9041- Result.set({VD, Frame->Index, Version});
9042- return true;
9043- }
9044- return Success(VD);
9045- }
9046- return false;
9047- }
90489037
90499038 return Success(*V, E);
90509039}
0 commit comments