@@ -211,25 +211,26 @@ static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
211
211
S.Note (VD->getLocation (), diag::note_declared_at);
212
212
}
213
213
214
- static bool CheckTemporary (InterpState &S, CodePtr OpPC, const Pointer &Ptr ,
214
+ static bool CheckTemporary (InterpState &S, CodePtr OpPC, const Block *B ,
215
215
AccessKinds AK) {
216
- if (auto ID = Ptr. getDeclID ()) {
217
- if (!Ptr. isStaticTemporary ( ))
216
+ if (B-> getDeclID ()) {
217
+ if (!(B-> isStatic () && B-> isTemporary () ))
218
218
return true ;
219
219
220
220
const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(
221
- Ptr. getDeclDesc ()->asExpr ());
221
+ B-> getDescriptor ()->asExpr ());
222
222
if (!MTE)
223
223
return true ;
224
224
225
225
// FIXME(perf): Since we do this check on every Load from a static
226
226
// temporary, it might make sense to cache the value of the
227
227
// isUsableInConstantExpressions call.
228
- if (!MTE-> isUsableInConstantExpressions (S. getASTContext () ) &&
229
- Ptr. block ()-> getEvalID () != S. Ctx . getEvalID ( )) {
228
+ if (B-> getEvalID () != S. Ctx . getEvalID ( ) &&
229
+ !MTE-> isUsableInConstantExpressions (S. getASTContext () )) {
230
230
const SourceInfo &E = S.Current ->getSource (OpPC);
231
231
S.FFDiag (E, diag::note_constexpr_access_static_temporary, 1 ) << AK;
232
- S.Note (Ptr.getDeclLoc (), diag::note_constexpr_temporary_here);
232
+ S.Note (B->getDescriptor ()->getLocation (),
233
+ diag::note_constexpr_temporary_here);
233
234
return false ;
234
235
}
235
236
}
@@ -658,17 +659,19 @@ static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
658
659
return false ;
659
660
}
660
661
661
- bool CheckInitialized (InterpState &S, CodePtr OpPC, const Pointer &Ptr,
662
- AccessKinds AK) {
662
+ bool DiagnoseUninitialized (InterpState &S, CodePtr OpPC, const Pointer &Ptr,
663
+ AccessKinds AK) {
663
664
assert (Ptr.isLive ());
665
+ assert (!Ptr.isInitialized ());
666
+ return DiagnoseUninitialized (S, OpPC, Ptr.isExtern (), Ptr.getDeclDesc (), AK);
667
+ }
664
668
665
- if (Ptr.isInitialized ())
666
- return true ;
667
-
668
- if (Ptr.isExtern () && S.checkingPotentialConstantExpression ())
669
+ bool DiagnoseUninitialized (InterpState &S, CodePtr OpPC, bool Extern,
670
+ const Descriptor *Desc, AccessKinds AK) {
671
+ if (Extern && S.checkingPotentialConstantExpression ())
669
672
return false ;
670
673
671
- if (const auto *VD = Ptr. getDeclDesc () ->asVarDecl ();
674
+ if (const auto *VD = Desc ->asVarDecl ();
672
675
VD && (VD->isConstexpr () || VD->hasGlobalStorage ())) {
673
676
674
677
if (VD == S.EvaluatingDecl &&
@@ -703,9 +706,9 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
703
706
return false ;
704
707
}
705
708
706
- static bool CheckLifetime (InterpState &S, CodePtr OpPC, const Pointer &Ptr ,
709
+ static bool CheckLifetime (InterpState &S, CodePtr OpPC, Lifetime LT ,
707
710
AccessKinds AK) {
708
- if (Ptr. getLifetime () == Lifetime::Started)
711
+ if (LT == Lifetime::Started)
709
712
return true ;
710
713
711
714
if (!S.checkingPotentialConstantExpression ()) {
@@ -715,11 +718,11 @@ static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
715
718
return false ;
716
719
}
717
720
718
- static bool CheckWeak (InterpState &S, CodePtr OpPC, const Pointer &Ptr ) {
719
- if (!Ptr. isWeak ())
721
+ static bool CheckWeak (InterpState &S, CodePtr OpPC, const Block *B ) {
722
+ if (!B-> isWeak ())
720
723
return true ;
721
724
722
- const auto *VD = Ptr. getDeclDesc ()->asVarDecl ();
725
+ const auto *VD = B-> getDescriptor ()->asVarDecl ();
723
726
assert (VD);
724
727
S.FFDiag (S.Current ->getLocation (OpPC), diag::note_constexpr_var_init_weak)
725
728
<< VD;
@@ -732,32 +735,56 @@ static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
732
735
// ones removed that are impossible on primitive global values.
733
736
// For example, since those can't be members of structs, they also can't
734
737
// be mutable.
735
- bool CheckGlobalLoad (InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
736
- if (!CheckExtern (S, OpPC, Ptr))
738
+ bool CheckGlobalLoad (InterpState &S, CodePtr OpPC, const Block *B) {
739
+ const auto &Desc =
740
+ *reinterpret_cast <const GlobalInlineDescriptor *>(B->rawData ());
741
+ if (!CheckExtern (S, OpPC, Pointer (const_cast <Block *>(B))))
737
742
return false ;
738
- if (!CheckConstant (S, OpPC, Ptr))
739
- return false ;
740
- if (!CheckDummy (S, OpPC, Ptr, AK_Read))
743
+ if (!CheckConstant (S, OpPC, B->getDescriptor ()))
741
744
return false ;
742
- if (!CheckInitialized (S, OpPC, Ptr , AK_Read))
745
+ if (!CheckDummy (S, OpPC, B , AK_Read))
743
746
return false ;
744
- if (!CheckTemporary (S, OpPC, Ptr, AK_Read))
747
+ if (Desc.InitState != GlobalInitState::Initialized)
748
+ return DiagnoseUninitialized (S, OpPC, B->isExtern (), B->getDescriptor (),
749
+ AK_Read);
750
+ if (!CheckTemporary (S, OpPC, B, AK_Read))
745
751
return false ;
746
- if (!CheckWeak (S, OpPC, Ptr ))
752
+ if (!CheckWeak (S, OpPC, B ))
747
753
return false ;
748
- if (!CheckVolatile (S, OpPC, Ptr, AK_Read))
754
+ if (B->getDescriptor ()->IsVolatile ) {
755
+ if (!S.getLangOpts ().CPlusPlus )
756
+ return Invalid (S, OpPC);
757
+
758
+ const ValueDecl *D = B->getDescriptor ()->asValueDecl ();
759
+ S.FFDiag (S.Current ->getLocation (OpPC),
760
+ diag::note_constexpr_access_volatile_obj, 1 )
761
+ << AK_Read << 1 << D;
762
+ S.Note (D->getLocation (), diag::note_constexpr_volatile_here) << 1 ;
749
763
return false ;
764
+ }
750
765
return true ;
751
766
}
752
767
753
768
// Similarly, for local loads.
754
- bool CheckLocalLoad (InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
755
- if (!CheckLifetime (S, OpPC, Ptr, AK_Read))
756
- return false ;
757
- if (!CheckInitialized (S, OpPC, Ptr, AK_Read))
758
- return false ;
759
- if (!CheckVolatile (S, OpPC, Ptr, AK_Read))
769
+ bool CheckLocalLoad (InterpState &S, CodePtr OpPC, const Block *B) {
770
+ assert (!B->isExtern ());
771
+ const auto &Desc = *reinterpret_cast <const InlineDescriptor *>(B->rawData ());
772
+ if (!CheckLifetime (S, OpPC, Desc.LifeState , AK_Read))
773
+ return false ;
774
+ if (!Desc.IsInitialized )
775
+ return DiagnoseUninitialized (S, OpPC, /* Extern=*/ false , B->getDescriptor (),
776
+ AK_Read);
777
+ if (B->getDescriptor ()->IsVolatile ) {
778
+ if (!S.getLangOpts ().CPlusPlus )
779
+ return Invalid (S, OpPC);
780
+
781
+ const ValueDecl *D = B->getDescriptor ()->asValueDecl ();
782
+ S.FFDiag (S.Current ->getLocation (OpPC),
783
+ diag::note_constexpr_access_volatile_obj, 1 )
784
+ << AK_Read << 1 << D;
785
+ S.Note (D->getLocation (), diag::note_constexpr_volatile_here) << 1 ;
760
786
return false ;
787
+ }
761
788
return true ;
762
789
}
763
790
@@ -769,19 +796,19 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
769
796
return false ;
770
797
if (!CheckConstant (S, OpPC, Ptr))
771
798
return false ;
772
- if (!CheckDummy (S, OpPC, Ptr, AK))
799
+ if (Ptr. isBlockPointer () && !CheckDummy (S, OpPC, Ptr. block () , AK))
773
800
return false ;
774
801
if (!CheckRange (S, OpPC, Ptr, AK))
775
802
return false ;
776
803
if (!CheckActive (S, OpPC, Ptr, AK))
777
804
return false ;
778
- if (!CheckLifetime (S, OpPC, Ptr, AK))
779
- return false ;
780
- if (!CheckInitialized (S, OpPC, Ptr, AK))
805
+ if (!CheckLifetime (S, OpPC, Ptr.getLifetime (), AK))
781
806
return false ;
782
- if (!CheckTemporary (S, OpPC, Ptr, AK))
807
+ if (!Ptr.isInitialized ())
808
+ return DiagnoseUninitialized (S, OpPC, Ptr, AK);
809
+ if (Ptr.isBlockPointer () && !CheckTemporary (S, OpPC, Ptr.block (), AK))
783
810
return false ;
784
- if (!CheckWeak (S, OpPC, Ptr))
811
+ if (Ptr. isBlockPointer () && !CheckWeak (S, OpPC, Ptr. block () ))
785
812
return false ;
786
813
if (!CheckMutable (S, OpPC, Ptr))
787
814
return false ;
@@ -798,21 +825,21 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
798
825
if (!CheckConstant (S, OpPC, Ptr))
799
826
return false ;
800
827
801
- if (!CheckDummy (S, OpPC, Ptr, AK_Read))
828
+ if (Ptr. isBlockPointer () && !CheckDummy (S, OpPC, Ptr. block () , AK_Read))
802
829
return false ;
803
830
if (!CheckExtern (S, OpPC, Ptr))
804
831
return false ;
805
832
if (!CheckRange (S, OpPC, Ptr, AK_Read))
806
833
return false ;
807
834
if (!CheckActive (S, OpPC, Ptr, AK_Read))
808
835
return false ;
809
- if (!CheckLifetime (S, OpPC, Ptr, AK_Read))
810
- return false ;
811
- if (!CheckInitialized (S, OpPC, Ptr, AK_Read))
836
+ if (!CheckLifetime (S, OpPC, Ptr.getLifetime (), AK_Read))
812
837
return false ;
813
- if (!CheckTemporary (S, OpPC, Ptr, AK_Read))
838
+ if (!Ptr.isInitialized ())
839
+ return DiagnoseUninitialized (S, OpPC, Ptr, AK_Read);
840
+ if (Ptr.isBlockPointer () && !CheckTemporary (S, OpPC, Ptr.block (), AK_Read))
814
841
return false ;
815
- if (!CheckWeak (S, OpPC, Ptr))
842
+ if (Ptr. isBlockPointer () && !CheckWeak (S, OpPC, Ptr. block () ))
816
843
return false ;
817
844
if (!CheckMutable (S, OpPC, Ptr))
818
845
return false ;
@@ -822,9 +849,9 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
822
849
bool CheckStore (InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
823
850
if (!CheckLive (S, OpPC, Ptr, AK_Assign))
824
851
return false ;
825
- if (!CheckDummy (S, OpPC, Ptr, AK_Assign))
852
+ if (Ptr. isBlockPointer () && !CheckDummy (S, OpPC, Ptr. block () , AK_Assign))
826
853
return false ;
827
- if (!CheckLifetime (S, OpPC, Ptr, AK_Assign))
854
+ if (!CheckLifetime (S, OpPC, Ptr. getLifetime () , AK_Assign))
828
855
return false ;
829
856
if (!CheckExtern (S, OpPC, Ptr))
830
857
return false ;
@@ -1098,12 +1125,11 @@ bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
1098
1125
return diagnoseUnknownDecl (S, OpPC, D);
1099
1126
}
1100
1127
1101
- bool CheckDummy (InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1102
- AccessKinds AK) {
1103
- if (!Ptr. isDummy ())
1128
+ bool CheckDummy (InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK) {
1129
+ const Descriptor *Desc = B-> getDescriptor ();
1130
+ if (!Desc-> isDummy ())
1104
1131
return true ;
1105
1132
1106
- const Descriptor *Desc = Ptr.getDeclDesc ();
1107
1133
const ValueDecl *D = Desc->asValueDecl ();
1108
1134
if (!D)
1109
1135
return false ;
@@ -1426,7 +1452,7 @@ static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func,
1426
1452
bool CheckDestructor (InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
1427
1453
if (!CheckLive (S, OpPC, Ptr, AK_Destroy))
1428
1454
return false ;
1429
- if (!CheckTemporary (S, OpPC, Ptr, AK_Destroy))
1455
+ if (!CheckTemporary (S, OpPC, Ptr. block () , AK_Destroy))
1430
1456
return false ;
1431
1457
if (!CheckRange (S, OpPC, Ptr, AK_Destroy))
1432
1458
return false ;
@@ -1749,7 +1775,7 @@ static void startLifetimeRecurse(const Pointer &Ptr) {
1749
1775
1750
1776
bool StartLifetime (InterpState &S, CodePtr OpPC) {
1751
1777
const auto &Ptr = S.Stk .peek <Pointer>();
1752
- if (!CheckDummy (S, OpPC, Ptr, AK_Destroy))
1778
+ if (Ptr. isBlockPointer () && !CheckDummy (S, OpPC, Ptr. block () , AK_Destroy))
1753
1779
return false ;
1754
1780
startLifetimeRecurse (Ptr.narrow ());
1755
1781
return true ;
@@ -1780,7 +1806,7 @@ static void endLifetimeRecurse(const Pointer &Ptr) {
1780
1806
// / Ends the lifetime of the peek'd pointer.
1781
1807
bool EndLifetime (InterpState &S, CodePtr OpPC) {
1782
1808
const auto &Ptr = S.Stk .peek <Pointer>();
1783
- if (!CheckDummy (S, OpPC, Ptr, AK_Destroy))
1809
+ if (Ptr. isBlockPointer () && !CheckDummy (S, OpPC, Ptr. block () , AK_Destroy))
1784
1810
return false ;
1785
1811
endLifetimeRecurse (Ptr.narrow ());
1786
1812
return true ;
@@ -1789,7 +1815,7 @@ bool EndLifetime(InterpState &S, CodePtr OpPC) {
1789
1815
// / Ends the lifetime of the pop'd pointer.
1790
1816
bool EndLifetimePop (InterpState &S, CodePtr OpPC) {
1791
1817
const auto &Ptr = S.Stk .pop <Pointer>();
1792
- if (!CheckDummy (S, OpPC, Ptr, AK_Destroy))
1818
+ if (Ptr. isBlockPointer () && !CheckDummy (S, OpPC, Ptr. block () , AK_Destroy))
1793
1819
return false ;
1794
1820
endLifetimeRecurse (Ptr.narrow ());
1795
1821
return true ;
@@ -1804,16 +1830,16 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
1804
1830
1805
1831
// Similar to CheckStore(), but with the additional CheckTemporary() call and
1806
1832
// the AccessKinds are different.
1807
- if (!CheckTemporary (S, OpPC, Ptr, AK_Construct))
1833
+ if (!CheckTemporary (S, OpPC, Ptr. block () , AK_Construct))
1808
1834
return false ;
1809
1835
if (!CheckLive (S, OpPC, Ptr, AK_Construct))
1810
1836
return false ;
1811
- if (!CheckDummy (S, OpPC, Ptr, AK_Construct))
1837
+ if (!CheckDummy (S, OpPC, Ptr. block () , AK_Construct))
1812
1838
return false ;
1813
1839
1814
1840
// CheckLifetime for this and all base pointers.
1815
1841
for (Pointer P = Ptr;;) {
1816
- if (!CheckLifetime (S, OpPC, P, AK_Construct))
1842
+ if (!CheckLifetime (S, OpPC, P. getLifetime () , AK_Construct))
1817
1843
return false ;
1818
1844
1819
1845
if (P.isRoot ())
0 commit comments