@@ -3492,11 +3492,33 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3492
3492
3493
3493
APValue::LValueBase Base(VD, Frame ? Frame->Index : 0, Version);
3494
3494
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
+
3495
3517
// If this is a local variable, dig out its value.
3496
3518
if (Frame) {
3497
3519
Result = Frame->getTemporary(VD, Version);
3498
3520
if (Result)
3499
- return true;
3521
+ return CheckUninitReference(/*IsLocalVariable=*/ true) ;
3500
3522
3501
3523
if (!isa<ParmVarDecl>(VD)) {
3502
3524
// Assume variables referenced within a lambda's call operator that were
@@ -3521,7 +3543,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3521
3543
// in-flight value.
3522
3544
if (Info.EvaluatingDecl == Base) {
3523
3545
Result = Info.EvaluatingDeclValue;
3524
- return true ;
3546
+ return CheckUninitReference(/*IsLocalVariable=*/false) ;
3525
3547
}
3526
3548
3527
3549
// P2280R4 struck the restriction that variable of reference type lifetime
@@ -3594,11 +3616,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3594
3616
// type so we can no longer assume we have an Init.
3595
3617
// Used to be C++20 [expr.const]p5.12:
3596
3618
// ... 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) {
3602
3620
Info.FFDiag(E, diag::note_constexpr_var_init_non_constant, 1) << VD;
3603
3621
NoteLValueLocation(Info, Base);
3604
3622
return false;
@@ -3636,18 +3654,14 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3636
3654
3637
3655
Result = VD->getEvaluatedValue();
3638
3656
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)
3648
3659
Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base);
3660
+ else
3661
+ return false;
3649
3662
}
3650
- return true;
3663
+
3664
+ return CheckUninitReference(/*IsLocalVariable=*/false);
3651
3665
}
3652
3666
3653
3667
/// Get the base index of the given base class within an APValue representing
@@ -8953,12 +8967,7 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
8953
8967
return Error(E);
8954
8968
}
8955
8969
8956
-
8957
8970
bool 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();
8962
8971
// If we are within a lambda's call operator, check whether the 'VD' referred
8963
8972
// to within 'E' actually represents a lambda-capture that maps to a
8964
8973
// 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) {
9025
9034
APValue *V;
9026
9035
if (!evaluateVarDeclInit(Info, E, VD, Frame, Version, V))
9027
9036
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
- }
9048
9037
9049
9038
return Success(*V, E);
9050
9039
}
0 commit comments