@@ -214,7 +214,9 @@ namespace {
214
214
assert(!isBaseAnAllocSizeCall(Base) &&
215
215
"Unsized arrays shouldn't appear here");
216
216
unsigned MostDerivedLength = 0;
217
- Type = getType(Base);
217
+ // The type of Base is a reference type if the base is a constexpr-unknown
218
+ // variable. In that case, look through the reference type.
219
+ Type = getType(Base).getNonReferenceType();
218
220
219
221
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
220
222
if (Type->isArrayType()) {
@@ -305,7 +307,7 @@ namespace {
305
307
: Invalid(false), IsOnePastTheEnd(false),
306
308
FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
307
309
MostDerivedPathLength(0), MostDerivedArraySize(0),
308
- MostDerivedType(T) {}
310
+ MostDerivedType(T.isNull() ? QualType() : T.getNonReferenceType() ) {}
309
311
310
312
SubobjectDesignator(ASTContext &Ctx, const APValue &V)
311
313
: Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false),
@@ -616,7 +618,6 @@ namespace {
616
618
typedef std::map<MapKeyTy, APValue> MapTy;
617
619
/// Temporaries - Temporary lvalues materialized within this stack frame.
618
620
MapTy Temporaries;
619
- MapTy ConstexprUnknownAPValues;
620
621
621
622
/// CallRange - The source range of the call expression for this call.
622
623
SourceRange CallRange;
@@ -691,9 +692,6 @@ namespace {
691
692
APValue &createTemporary(const KeyT *Key, QualType T,
692
693
ScopeKind Scope, LValue &LV);
693
694
694
- APValue &createConstexprUnknownAPValues(const VarDecl *Key,
695
- APValue::LValueBase Base);
696
-
697
695
/// Allocate storage for a parameter of a function call made in this frame.
698
696
APValue &createParam(CallRef Args, const ParmVarDecl *PVD, LValue &LV);
699
697
@@ -1886,7 +1884,8 @@ namespace {
1886
1884
return;
1887
1885
}
1888
1886
if (checkSubobject(Info, E, CSK_ArrayToPointer)) {
1889
- assert(getType(Base)->isPointerType() || getType(Base)->isArrayType());
1887
+ assert(getType(Base).getNonReferenceType()->isPointerType() ||
1888
+ getType(Base).getNonReferenceType()->isArrayType());
1890
1889
Designator.FirstEntryIsAnUnsizedArray = true;
1891
1890
Designator.addUnsizedArrayUnchecked(ElemTy);
1892
1891
}
@@ -2131,15 +2130,6 @@ APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T,
2131
2130
return createLocal(Base, Key, T, Scope);
2132
2131
}
2133
2132
2134
- APValue &
2135
- CallStackFrame::createConstexprUnknownAPValues(const VarDecl *Key,
2136
- APValue::LValueBase Base) {
2137
- APValue &Result = ConstexprUnknownAPValues[MapKeyTy(Key, Base.getVersion())];
2138
- Result = APValue(Base, CharUnits::Zero(), APValue::ConstexprUnknown{});
2139
-
2140
- return Result;
2141
- }
2142
-
2143
2133
/// Allocate storage for a parameter of a function call made in this frame.
2144
2134
APValue &CallStackFrame::createParam(CallRef Args, const ParmVarDecl *PVD,
2145
2135
LValue &LV) {
@@ -3670,7 +3660,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3670
3660
APValue::LValueBase Base(VD, Frame ? Frame->Index : 0, Version);
3671
3661
3672
3662
auto CheckUninitReference = [&](bool IsLocalVariable) {
3673
- if (!Result->hasValue() && VD->getType()->isReferenceType()) {
3663
+ if (!Result || (!Result ->hasValue() && VD->getType()->isReferenceType() )) {
3674
3664
// C++23 [expr.const]p8
3675
3665
// ... For such an object that is not usable in constant expressions, the
3676
3666
// dynamic type of the object is constexpr-unknown. For such a reference
@@ -3686,7 +3676,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3686
3676
Info.FFDiag(E, diag::note_constexpr_use_uninit_reference);
3687
3677
return false;
3688
3678
}
3689
- Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base) ;
3679
+ Result = nullptr ;
3690
3680
}
3691
3681
return true;
3692
3682
};
@@ -3729,7 +3719,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3729
3719
// ... its lifetime began within the evaluation of E;
3730
3720
if (isa<ParmVarDecl>(VD)) {
3731
3721
if (AllowConstexprUnknown) {
3732
- Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base) ;
3722
+ Result = nullptr ;
3733
3723
return true;
3734
3724
}
3735
3725
@@ -3836,12 +3826,8 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
3836
3826
3837
3827
Result = VD->getEvaluatedValue();
3838
3828
3839
- if (!Result) {
3840
- if (AllowConstexprUnknown)
3841
- Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base);
3842
- else
3843
- return false;
3844
- }
3829
+ if (!Result && !AllowConstexprUnknown)
3830
+ return false;
3845
3831
3846
3832
return CheckUninitReference(/*IsLocalVariable=*/false);
3847
3833
}
@@ -4124,11 +4110,6 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
4124
4110
const FieldDecl *LastField = nullptr;
4125
4111
const FieldDecl *VolatileField = nullptr;
4126
4112
4127
- // C++23 [expr.const]p8 If we have an unknown reference or pointers and it
4128
- // does not have a value then bail out.
4129
- if (O->allowConstexprUnknown() && !O->hasValue())
4130
- return false;
4131
-
4132
4113
// Walk the designator's path to find the subobject.
4133
4114
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
4134
4115
// Reading an indeterminate value is undefined, but assigning over one is OK.
@@ -4668,6 +4649,15 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
4668
4649
4669
4650
if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
4670
4651
return CompleteObject();
4652
+ // If evaluateVarDeclInit sees a constexpr-unknown variable, it returns
4653
+ // a null BaseVal. Any constexpr-unknown variable seen here is an error:
4654
+ // we can't access a constexpr-unknown object.
4655
+ if (!BaseVal) {
4656
+ Info.FFDiag(E, diag::note_constexpr_access_unknown_variable, 1)
4657
+ << AK << VD;
4658
+ Info.Note(VD->getLocation(), diag::note_declared_at);
4659
+ return CompleteObject();
4660
+ }
4671
4661
} else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
4672
4662
std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
4673
4663
if (!Alloc) {
@@ -6234,15 +6224,6 @@ struct CheckDynamicTypeHandler {
6234
6224
/// dynamic type.
6235
6225
static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This,
6236
6226
AccessKinds AK, bool Polymorphic) {
6237
- // We are not allowed to invoke a virtual function whose dynamic type
6238
- // is constexpr-unknown, so stop early and let this fail later on if we
6239
- // attempt to do so.
6240
- // C++23 [expr.const]p5.6
6241
- // an invocation of a virtual function ([class.virtual]) for an object whose
6242
- // dynamic type is constexpr-unknown;
6243
- if (This.allowConstexprUnknown())
6244
- return true;
6245
-
6246
6227
if (This.Designator.Invalid)
6247
6228
return false;
6248
6229
@@ -6316,9 +6297,7 @@ static std::optional<DynamicType> ComputeDynamicType(EvalInfo &Info,
6316
6297
// meaningful dynamic type. (We consider objects of non-class type to have no
6317
6298
// dynamic type.)
6318
6299
if (!checkDynamicType(Info, E, This, AK,
6319
- (AK == AK_TypeId
6320
- ? (E->getType()->isReferenceType() ? true : false)
6321
- : true)))
6300
+ AK != AK_TypeId || This.AllowConstexprUnknown))
6322
6301
return std::nullopt;
6323
6302
6324
6303
if (This.Designator.Invalid)
@@ -9271,6 +9250,12 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
9271
9250
if (!evaluateVarDeclInit(Info, E, VD, Frame, Version, V))
9272
9251
return false;
9273
9252
9253
+ if (!V) {
9254
+ Result.set(VD);
9255
+ Result.AllowConstexprUnknown = true;
9256
+ return true;
9257
+ }
9258
+
9274
9259
return Success(*V, E);
9275
9260
}
9276
9261
0 commit comments