@@ -5828,3 +5828,210 @@ void ClangImporter::diagnoseMemberValue(const DeclName &name,
5828
5828
}
5829
5829
}
5830
5830
}
5831
+
5832
+ static bool hasImportAsRefAttr (const clang::RecordDecl *decl) {
5833
+ return decl->hasAttrs () && llvm::any_of (decl->getAttrs (), [](auto *attr) {
5834
+ if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
5835
+ return swiftAttr->getAttribute () == " import_foreign_reference" ;
5836
+ return false ;
5837
+ });
5838
+ }
5839
+
5840
+ static bool hasOwnedValueAttr (const clang::RecordDecl *decl) {
5841
+ if (decl->getNameAsString () == " basic_string" ||
5842
+ decl->getNameAsString () == " vector" )
5843
+ return true ;
5844
+
5845
+ return decl->hasAttrs () && llvm::any_of (decl->getAttrs (), [](auto *attr) {
5846
+ if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
5847
+ return swiftAttr->getAttribute () == " import_owned_value" ;
5848
+ return false ;
5849
+ });
5850
+ }
5851
+
5852
+ static bool hasUnsafeAPIAttr (const clang::Decl *decl) {
5853
+ return decl->hasAttrs () && llvm::any_of (decl->getAttrs (), [](auto *attr) {
5854
+ if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
5855
+ return swiftAttr->getAttribute () == " import_unsafe_api" ;
5856
+ return false ;
5857
+ });
5858
+ }
5859
+
5860
+ // / Recursively checks that there are no pointers in any fields or base classes.
5861
+ // / Does not check C++ records with specific API annotations.
5862
+ static bool hasPointerInSubobjects (const clang::CXXRecordDecl *decl) {
5863
+ auto checkType = [](clang::QualType t) {
5864
+ if (t->isPointerType ())
5865
+ return false ;
5866
+
5867
+ if (auto recordType = dyn_cast<clang::RecordType>(t)) {
5868
+ if (auto cxxRecord =
5869
+ dyn_cast<clang::CXXRecordDecl>(recordType->getDecl ())) {
5870
+ if (hasImportAsRefAttr (cxxRecord) || hasOwnedValueAttr (cxxRecord) ||
5871
+ hasUnsafeAPIAttr (cxxRecord))
5872
+ return true ;
5873
+
5874
+ if (!hasPointerInSubobjects (cxxRecord))
5875
+ return false ;
5876
+ }
5877
+ }
5878
+
5879
+ return true ;
5880
+ };
5881
+
5882
+ for (auto field : decl->fields ()) {
5883
+ if (!checkType (field->getType ()))
5884
+ return false ;
5885
+ }
5886
+
5887
+ for (auto base : decl->bases ()) {
5888
+ if (!checkType (base.getType ()))
5889
+ return false ;
5890
+ }
5891
+
5892
+ return true ;
5893
+ }
5894
+
5895
+ // / Recursively checks that there are no user-provided copy constructors or
5896
+ // / destructors in any fields or base classes.
5897
+ // / Does not check C++ records with specific API annotations.
5898
+ static bool isSufficientlyTrivial (const clang::CXXRecordDecl *decl) {
5899
+ if (decl->hasUserDeclaredCopyConstructor () ||
5900
+ decl->hasUserDeclaredCopyAssignment () ||
5901
+ decl->hasUserDeclaredDestructor ())
5902
+ return false ;
5903
+
5904
+ auto checkType = [](clang::QualType t) {
5905
+ if (auto recordType = dyn_cast<clang::RecordType>(t)) {
5906
+ if (auto cxxRecord =
5907
+ dyn_cast<clang::CXXRecordDecl>(recordType->getDecl ())) {
5908
+ if (hasImportAsRefAttr (cxxRecord) || hasOwnedValueAttr (cxxRecord) ||
5909
+ hasUnsafeAPIAttr (cxxRecord))
5910
+ return true ;
5911
+
5912
+ if (!isSufficientlyTrivial (cxxRecord))
5913
+ return false ;
5914
+ }
5915
+ }
5916
+
5917
+ return true ;
5918
+ };
5919
+
5920
+ for (auto field : decl->fields ()) {
5921
+ if (!checkType (field->getType ()))
5922
+ return false ;
5923
+ }
5924
+
5925
+ for (auto base : decl->bases ()) {
5926
+ if (!checkType (base.getType ()))
5927
+ return false ;
5928
+ }
5929
+
5930
+ return true ;
5931
+ }
5932
+
5933
+ // / Checks if a record provides the required value type lifetime operations
5934
+ // / (copy and destroy).
5935
+ static bool hasRequiredValueTypeOperations (const clang::CXXRecordDecl *decl) {
5936
+ if (auto dtor = decl->getDestructor ()) {
5937
+ if (dtor->isDeleted () || dtor->getAccess () != clang::AS_public) {
5938
+ return false ;
5939
+ }
5940
+ }
5941
+
5942
+ // If we have no way of copying the type we can't import the class
5943
+ // at all because we cannot express the correct semantics as a swift
5944
+ // struct.
5945
+ if (llvm::any_of (decl->ctors (), [](clang::CXXConstructorDecl *ctor) {
5946
+ return ctor->isCopyConstructor () &&
5947
+ (ctor->isDeleted () || ctor->getAccess () != clang::AS_public);
5948
+ }))
5949
+ return false ;
5950
+
5951
+ return true ;
5952
+ }
5953
+
5954
+ CxxRecordSemanticsKind
5955
+ CxxRecordSemantics::evaluate (Evaluator &evaluator,
5956
+ CxxRecordSemanticsDescriptor desc) const {
5957
+ const auto *decl = desc.decl ;
5958
+
5959
+ // Hard-coded special cases from the standard library (this will go away once
5960
+ // API notes support namespaces).
5961
+ if (decl->getNameAsString () == " basic_string" ||
5962
+ decl->getNameAsString () == " vector" )
5963
+ return CxxRecordSemanticsKind::Owned;
5964
+
5965
+ if (hasImportAsRefAttr (decl))
5966
+ return CxxRecordSemanticsKind::Reference;
5967
+
5968
+ // TODO: diagnose if the decl also has any attrs.
5969
+ if (hasRequiredValueTypeOperations (decl))
5970
+ return CxxRecordSemanticsKind::UnsafeLifetimeOperation;
5971
+
5972
+ if (hasUnsafeAPIAttr (decl))
5973
+ return CxxRecordSemanticsKind::ExplicitlyUnsafe;
5974
+
5975
+ if (hasOwnedValueAttr (decl))
5976
+ return CxxRecordSemanticsKind::Owned;
5977
+
5978
+ if (!isSufficientlyTrivial (decl))
5979
+ return CxxRecordSemanticsKind::UnsafeLifetimeOperation;
5980
+
5981
+ if (hasPointerInSubobjects (decl))
5982
+ return CxxRecordSemanticsKind::UnsafePointerMember;
5983
+
5984
+ return CxxRecordSemanticsKind::Trivial;
5985
+ }
5986
+
5987
+ // TODO: rename to "is acceptable use of cxx record" (as some unsafe uses are OK).
5988
+ bool
5989
+ IsSafeUseOfCxxRecord::evaluate (Evaluator &evaluator,
5990
+ SafeUseOfCxxRecordDescriptor desc) const {
5991
+ const clang::CXXRecordDecl *decl = desc.recordDecl ;
5992
+
5993
+ auto semanticsKind = evaluateOrDefault (evaluator,
5994
+ CxxRecordSemantics ({decl}), {});
5995
+
5996
+ // Always unsafe.
5997
+ if (semanticsKind == CxxRecordSemanticsKind::UnsafeLifetimeOperation)
5998
+ return false ;
5999
+
6000
+ // Always OK.
6001
+ if (semanticsKind == CxxRecordSemanticsKind::Trivial ||
6002
+ semanticsKind == CxxRecordSemanticsKind::Reference ||
6003
+ semanticsKind == CxxRecordSemanticsKind::Owned ||
6004
+ // Maybe in the future this should warn.
6005
+ semanticsKind == CxxRecordSemanticsKind::ExplicitlyUnsafe)
6006
+ return true ;
6007
+
6008
+ assert (semanticsKind == CxxRecordSemanticsKind::UnsafePointerMember);
6009
+ // We can't dis-allow *all* APIs that potentially return unsafe projections
6010
+ // because this would break ObjC interop. So only do this when it's a known
6011
+ // C++ API (maybe this could warn in a specific compiler mode, though).
6012
+ return desc.kind != CxxRecordUseKind::CxxReturnType;
6013
+ }
6014
+
6015
+ void swift::simple_display (llvm::raw_ostream &out,
6016
+ CxxRecordSemanticsDescriptor desc) {
6017
+ out << " Matching API semantics of C++ record '"
6018
+ << desc.decl ->getNameAsString ()
6019
+ << " '.\n " ;
6020
+ }
6021
+
6022
+ SourceLoc
6023
+ swift::extractNearestSourceLoc (CxxRecordSemanticsDescriptor desc) {
6024
+ return SourceLoc ();
6025
+ }
6026
+
6027
+ void swift::simple_display (llvm::raw_ostream &out,
6028
+ SafeUseOfCxxRecordDescriptor desc) {
6029
+ out << " Checking if '"
6030
+ << desc.recordDecl ->getNameAsString ()
6031
+ << " ' is safe to use in context.\n " ;
6032
+ }
6033
+
6034
+ SourceLoc
6035
+ swift::extractNearestSourceLoc (SafeUseOfCxxRecordDescriptor desc) {
6036
+ return SourceLoc ();
6037
+ }
0 commit comments