@@ -253,9 +253,11 @@ bool conflicting(ASTContext &ctx,
253
253
254
254
// / Decl - Base class for all declarations in Swift.
255
255
class alignas (1 << DeclAlignInBits) Decl {
256
+ public:
256
257
enum class ValidationState {
257
258
Unchecked,
258
259
Checking,
260
+ CheckingWithValidSignature,
259
261
Checked,
260
262
};
261
263
@@ -796,33 +798,51 @@ class alignas(1 << DeclAlignInBits) Decl {
796
798
Bits.Decl .EarlyAttrValidation = validated;
797
799
}
798
800
799
- // / Whether the declaration has a valid interface type and
800
- // / generic signature.
801
- bool isBeingValidated () const {
802
- return Bits.Decl .ValidationState == unsigned (ValidationState::Checking);
801
+ // / Get the validation state.
802
+ ValidationState getValidationState () const {
803
+ return ValidationState (Bits.Decl .ValidationState );
803
804
}
804
805
805
- // / Toggle whether or not the declaration is being validated.
806
- void setIsBeingValidated (bool ibv = true ) {
807
- if (ibv) {
808
- assert (Bits.Decl .ValidationState == unsigned (ValidationState::Unchecked));
809
- Bits.Decl .ValidationState = unsigned (ValidationState::Checking);
810
- } else {
811
- assert (Bits.Decl .ValidationState == unsigned (ValidationState::Checking));
812
- Bits.Decl .ValidationState = unsigned (ValidationState::Checked);
806
+ private:
807
+ friend class DeclValidationRAII ;
808
+
809
+ // / Set the validation state.
810
+ void setValidationState (ValidationState VS) {
811
+ assert (VS > getValidationState () && " Validation is unidirectional" );
812
+ Bits.Decl .ValidationState = unsigned (VS);
813
+ }
814
+
815
+ public:
816
+ // / Whether the declaration is in the middle of validation or not.
817
+ bool isBeingValidated () const {
818
+ switch (getValidationState ()) {
819
+ case ValidationState::Unchecked:
820
+ case ValidationState::Checked:
821
+ return false ;
822
+ default :
823
+ return true ;
813
824
}
814
825
}
815
826
827
+ // / Update the validation state for the declaration to allow access to the
828
+ // / generic signature.
829
+ void setSignatureIsValidated () {
830
+ assert (getValidationState () == ValidationState::Checking);
831
+ setValidationState (ValidationState::CheckingWithValidSignature);
832
+ }
833
+
816
834
bool hasValidationStarted () const {
817
- return Bits. Decl . ValidationState >= unsigned ( ValidationState::Checking) ;
835
+ return getValidationState () > ValidationState::Unchecked ;
818
836
}
819
837
820
- // / Manually indicate that validation has started for the declaration.
838
+ // / Manually indicate that validation is complete for the declaration. For
839
+ // / example: during importing, code synthesis, or derived conformances.
821
840
// /
822
- // / This is implied by setIsBeingValidated(true) (i.e. starting validation)
823
- // / and so rarely needs to be called directly.
824
- void setValidationStarted () {
825
- if (Bits.Decl .ValidationState != unsigned (ValidationState::Checking))
841
+ // / For normal code validation, please use DeclValidationRAII instead.
842
+ // /
843
+ // / FIXME -- Everything should use DeclValidationRAII instead of this.
844
+ void setValidationToChecked () {
845
+ if (!isBeingValidated ())
826
846
Bits.Decl .ValidationState = unsigned (ValidationState::Checked);
827
847
}
828
848
@@ -924,6 +944,25 @@ class alignas(1 << DeclAlignInBits) Decl {
924
944
}
925
945
};
926
946
947
+ // / \brief Use RAII to track Decl validation progress and non-reentrancy.
948
+ class DeclValidationRAII {
949
+ Decl *D;
950
+
951
+ public:
952
+ DeclValidationRAII (const DeclValidationRAII &) = delete ;
953
+ DeclValidationRAII (DeclValidationRAII &&) = delete ;
954
+ void operator =(const DeclValidationRAII &) = delete ;
955
+ void operator =(DeclValidationRAII &&) = delete ;
956
+
957
+ DeclValidationRAII (Decl *decl) : D(decl) {
958
+ D->setValidationState (Decl::ValidationState::Checking);
959
+ }
960
+
961
+ ~DeclValidationRAII () {
962
+ D->setValidationState (Decl::ValidationState::Checked);
963
+ }
964
+ };
965
+
927
966
// / \brief Allocates memory for a Decl with the given \p baseSize. If necessary,
928
967
// / it includes additional space immediately preceding the Decl for a ClangNode.
929
968
// / \note \p baseSize does not need to include space for a ClangNode if
@@ -1677,9 +1716,9 @@ class ExtensionDecl final : public GenericContext, public Decl,
1677
1716
// / Retrieve one of the types listed in the "inherited" clause.
1678
1717
Type getInheritedType (unsigned index) const ;
1679
1718
1680
- // / Whether we have fully checked the extension.
1719
+ // / Whether we have fully checked the extension signature .
1681
1720
bool hasValidSignature () const {
1682
- return hasValidationStarted () && ! isBeingValidated () ;
1721
+ return getValidationState () > ValidationState::CheckingWithValidSignature ;
1683
1722
}
1684
1723
1685
1724
bool hasDefaultAccessLevel () const {
0 commit comments