@@ -744,6 +744,15 @@ namespace {
744
744
/// evaluated, if any.
745
745
APValue::LValueBase EvaluatingDecl;
746
746
747
+ enum class EvaluatingDeclKind {
748
+ None,
749
+ /// We're evaluating the construction of EvaluatingDecl.
750
+ Ctor,
751
+ /// We're evaluating the destruction of EvaluatingDecl.
752
+ Dtor,
753
+ };
754
+ EvaluatingDeclKind IsEvaluatingDecl = EvaluatingDeclKind::None;
755
+
747
756
/// EvaluatingDeclValue - This is the value being constructed for the
748
757
/// declaration whose initializer is being evaluated, if any.
749
758
APValue *EvaluatingDeclValue;
@@ -902,8 +911,10 @@ namespace {
902
911
discardCleanups();
903
912
}
904
913
905
- void setEvaluatingDecl (APValue::LValueBase Base, APValue &Value) {
914
+ void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
915
+ EvaluatingDeclKind EDK = EvaluatingDeclKind::Ctor) {
906
916
EvaluatingDecl = Base;
917
+ IsEvaluatingDecl = EDK;
907
918
EvaluatingDeclValue = &Value;
908
919
}
909
920
@@ -2913,8 +2924,8 @@ static bool isReadByLvalueToRvalueConversion(QualType T) {
2913
2924
2914
2925
/// Diagnose an attempt to read from any unreadable field within the specified
2915
2926
/// type, which might be a class type.
2916
- static bool diagnoseUnreadableFields (EvalInfo &Info, const Expr *E,
2917
- QualType T) {
2927
+ static bool diagnoseMutableFields (EvalInfo &Info, const Expr *E, AccessKinds AK ,
2928
+ QualType T) {
2918
2929
CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
2919
2930
if (!RD)
2920
2931
return false;
@@ -2929,25 +2940,26 @@ static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E,
2929
2940
// FIXME: Add core issue number for the union case.
2930
2941
if (Field->isMutable() &&
2931
2942
(RD->isUnion() || isReadByLvalueToRvalueConversion(Field->getType()))) {
2932
- Info.FFDiag (E, diag::note_constexpr_ltor_mutable , 1 ) << Field;
2943
+ Info.FFDiag(E, diag::note_constexpr_access_mutable , 1) << AK << Field;
2933
2944
Info.Note(Field->getLocation(), diag::note_declared_at);
2934
2945
return true;
2935
2946
}
2936
2947
2937
- if (diagnoseUnreadableFields (Info, E, Field->getType ()))
2948
+ if (diagnoseMutableFields (Info, E, AK , Field->getType()))
2938
2949
return true;
2939
2950
}
2940
2951
2941
2952
for (auto &BaseSpec : RD->bases())
2942
- if (diagnoseUnreadableFields (Info, E, BaseSpec.getType ()))
2953
+ if (diagnoseMutableFields (Info, E, AK , BaseSpec.getType()))
2943
2954
return true;
2944
2955
2945
2956
// All mutable fields were empty, and thus not actually read.
2946
2957
return false;
2947
2958
}
2948
2959
2949
2960
static bool lifetimeStartedInEvaluation(EvalInfo &Info,
2950
- APValue::LValueBase Base) {
2961
+ APValue::LValueBase Base,
2962
+ bool MutableSubobject = false) {
2951
2963
// A temporary we created.
2952
2964
if (Base.getCallIndex())
2953
2965
return true;
@@ -2956,19 +2968,42 @@ static bool lifetimeStartedInEvaluation(EvalInfo &Info,
2956
2968
if (!Evaluating)
2957
2969
return false;
2958
2970
2959
- // The variable whose initializer we're evaluating.
2960
- if (auto *BaseD = Base.dyn_cast <const ValueDecl*>())
2961
- if (declaresSameEntity (Evaluating, BaseD))
2962
- return true ;
2971
+ auto *BaseD = Base.dyn_cast<const ValueDecl*>();
2963
2972
2964
- // A temporary lifetime-extended by the variable whose initializer we're
2965
- // evaluating.
2966
- if (auto *BaseE = Base.dyn_cast <const Expr *>())
2967
- if (auto *BaseMTE = dyn_cast<MaterializeTemporaryExpr>(BaseE))
2968
- if (declaresSameEntity (BaseMTE->getExtendingDecl (), Evaluating))
2969
- return true ;
2973
+ switch (Info.IsEvaluatingDecl) {
2974
+ case EvalInfo::EvaluatingDeclKind::None:
2975
+ return false;
2970
2976
2971
- return false ;
2977
+ case EvalInfo::EvaluatingDeclKind::Ctor:
2978
+ // The variable whose initializer we're evaluating.
2979
+ if (BaseD)
2980
+ return declaresSameEntity(Evaluating, BaseD);
2981
+
2982
+ // A temporary lifetime-extended by the variable whose initializer we're
2983
+ // evaluating.
2984
+ if (auto *BaseE = Base.dyn_cast<const Expr *>())
2985
+ if (auto *BaseMTE = dyn_cast<MaterializeTemporaryExpr>(BaseE))
2986
+ return declaresSameEntity(BaseMTE->getExtendingDecl(), Evaluating);
2987
+ return false;
2988
+
2989
+ case EvalInfo::EvaluatingDeclKind::Dtor:
2990
+ // C++2a [expr.const]p6:
2991
+ // [during constant destruction] the lifetime of a and its non-mutable
2992
+ // subobjects (but not its mutable subobjects) [are] considered to start
2993
+ // within e.
2994
+ //
2995
+ // FIXME: We can meaningfully extend this to cover non-const objects, but
2996
+ // we will need special handling: we should be able to access only
2997
+ // subobjects of such objects that are themselves declared const.
2998
+ if (!BaseD ||
2999
+ !(BaseD->getType().isConstQualified() ||
3000
+ BaseD->getType()->isReferenceType()) ||
3001
+ MutableSubobject)
3002
+ return false;
3003
+ return declaresSameEntity(Evaluating, BaseD);
3004
+ }
3005
+
3006
+ llvm_unreachable("unknown evaluating decl kind");
2972
3007
}
2973
3008
2974
3009
namespace {
@@ -2986,13 +3021,13 @@ struct CompleteObject {
2986
3021
CompleteObject(APValue::LValueBase Base, APValue *Value, QualType Type)
2987
3022
: Base(Base), Value(Value), Type(Type) {}
2988
3023
2989
- bool mayReadMutableMembers (EvalInfo &Info) const {
3024
+ bool mayAccessMutableMembers (EvalInfo &Info, AccessKinds AK ) const {
2990
3025
// In C++14 onwards, it is permitted to read a mutable member whose
2991
3026
// lifetime began within the evaluation.
2992
3027
// FIXME: Should we also allow this in C++11?
2993
3028
if (!Info.getLangOpts().CPlusPlus14)
2994
3029
return false;
2995
- return lifetimeStartedInEvaluation (Info, Base);
3030
+ return lifetimeStartedInEvaluation(Info, Base, /*MutableSubobject*/true );
2996
3031
}
2997
3032
2998
3033
explicit operator bool() const { return !Type.isNull(); }
@@ -3097,9 +3132,9 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
3097
3132
// things we need to check: if there are any mutable subobjects, we
3098
3133
// cannot perform this read. (This only happens when performing a trivial
3099
3134
// copy or assignment.)
3100
- if (ObjType->isRecordType () && isRead (handler. AccessKind ) &&
3101
- !Obj.mayReadMutableMembers (Info) &&
3102
- diagnoseUnreadableFields (Info, E, ObjType))
3135
+ if (ObjType->isRecordType() &&
3136
+ !Obj.mayAccessMutableMembers (Info, handler.AccessKind ) &&
3137
+ diagnoseMutableFields (Info, E, handler.AccessKind , ObjType))
3103
3138
return handler.failed();
3104
3139
}
3105
3140
@@ -3167,10 +3202,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
3167
3202
: O->getComplexFloatReal(), ObjType);
3168
3203
}
3169
3204
} else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
3170
- if (Field->isMutable () && isRead (handler. AccessKind ) &&
3171
- !Obj.mayReadMutableMembers (Info)) {
3172
- Info.FFDiag (E, diag::note_constexpr_ltor_mutable , 1 )
3173
- << Field;
3205
+ if (Field->isMutable() &&
3206
+ !Obj.mayAccessMutableMembers (Info, handler.AccessKind )) {
3207
+ Info.FFDiag(E, diag::note_constexpr_access_mutable , 1)
3208
+ << handler.AccessKind << Field;
3174
3209
Info.Note(Field->getLocation(), diag::note_declared_at);
3175
3210
return handler.failed();
3176
3211
}
@@ -3427,8 +3462,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
3427
3462
// the variable we're reading must be const.
3428
3463
if (!Frame) {
3429
3464
if (Info.getLangOpts().CPlusPlus14 &&
3430
- declaresSameEntity (
3431
- VD, Info.EvaluatingDecl .dyn_cast <const ValueDecl *>())) {
3465
+ lifetimeStartedInEvaluation(Info, LVal.Base)) {
3432
3466
// OK, we can read and modify an object if we're in the process of
3433
3467
// evaluating its initializer, because its lifetime began in this
3434
3468
// evaluation.
@@ -3518,11 +3552,14 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
3518
3552
// int x = ++r;
3519
3553
// constexpr int k = r;
3520
3554
// Therefore we use the C++14 rules in C++11 too.
3521
- const ValueDecl *VD = Info.EvaluatingDecl .dyn_cast <const ValueDecl*>();
3522
- const ValueDecl *ED = MTE->getExtendingDecl ();
3555
+ //
3556
+ // Note that temporaries whose lifetimes began while evaluating a
3557
+ // variable's constructor are not usable while evaluating the
3558
+ // corresponding destructor, not even if they're of const-qualified
3559
+ // types.
3523
3560
if (!(BaseType.isConstQualified() &&
3524
3561
BaseType->isIntegralOrEnumerationType()) &&
3525
- !(VD && VD-> getCanonicalDecl () == ED-> getCanonicalDecl () )) {
3562
+ !lifetimeStartedInEvaluation(Info, LVal.Base )) {
3526
3563
if (!IsAccess)
3527
3564
return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
3528
3565
Info.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
@@ -13282,6 +13319,41 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
13282
13319
CheckMemoryLeaks(Info);
13283
13320
}
13284
13321
13322
+ bool VarDecl::evaluateDestruction(
13323
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
13324
+ assert(getEvaluatedValue() && !getEvaluatedValue()->isAbsent() &&
13325
+ "cannot evaluate destruction of non-constant-initialized variable");
13326
+
13327
+ Expr::EvalStatus EStatus;
13328
+ EStatus.Diag = &Notes;
13329
+
13330
+ // Make a copy of the value for the destructor to mutate.
13331
+ APValue DestroyedValue = *getEvaluatedValue();
13332
+
13333
+ EvalInfo Info(getASTContext(), EStatus, EvalInfo::EM_ConstantExpression);
13334
+ Info.setEvaluatingDecl(this, DestroyedValue,
13335
+ EvalInfo::EvaluatingDeclKind::Dtor);
13336
+ Info.InConstantContext = true;
13337
+
13338
+ SourceLocation DeclLoc = getLocation();
13339
+ QualType DeclTy = getType();
13340
+
13341
+ LValue LVal;
13342
+ LVal.set(this);
13343
+
13344
+ // FIXME: Consider storing whether this variable has constant destruction in
13345
+ // the EvaluatedStmt so that CodeGen can query it.
13346
+ if (!HandleDestruction(Info, DeclLoc, LVal.Base, DestroyedValue, DeclTy) ||
13347
+ EStatus.HasSideEffects)
13348
+ return false;
13349
+
13350
+ if (!Info.discardCleanups())
13351
+ llvm_unreachable("Unhandled cleanup; missing full expression marker?");
13352
+
13353
+ ensureEvaluatedStmt()->HasConstantDestruction = true;
13354
+ return true;
13355
+ }
13356
+
13285
13357
/// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
13286
13358
/// constant folded, but discard the result.
13287
13359
bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const {
0 commit comments