|
18 | 18 | #include "swift/AST/ProtocolConformance.h" |
19 | 19 | #include "swift/Basic/Assertions.h" |
20 | 20 | #include "swift/ClangImporter/ClangImporterRequests.h" |
| 21 | +#include "clang/AST/ASTContext.h" |
21 | 22 | #include "clang/AST/CXXInheritance.h" |
| 23 | +#include "clang/AST/Decl.h" |
| 24 | +#include "clang/AST/DeclCXX.h" |
22 | 25 | #include "clang/Sema/DelayedDiagnostic.h" |
23 | 26 | #include "clang/Sema/Lookup.h" |
24 | 27 | #include "clang/Sema/Overload.h" |
@@ -62,23 +65,22 @@ static CxxStdType identifyCxxStdTypeByName(StringRef name) { |
62 | 65 |
|
63 | 66 | static const clang::TypeDecl * |
64 | 67 | lookupCxxTypeMember(clang::Sema &Sema, const clang::CXXRecordDecl *Rec, |
65 | | - StringRef name) { |
| 68 | + StringRef name, bool mustBeComplete = false) { |
66 | 69 | auto R = clang::LookupResult(Sema, &Sema.PP.getIdentifierTable().get(name), |
67 | 70 | clang::SourceLocation(), |
68 | 71 | clang::Sema::LookupMemberName); |
69 | 72 | R.suppressDiagnostics(); |
70 | | - |
71 | 73 | auto *Ctx = static_cast<const clang::DeclContext *>(Rec); |
72 | 74 | Sema.LookupQualifiedName(R, const_cast<clang::DeclContext *>(Ctx)); |
73 | 75 |
|
74 | | - if (R.isSingleResult()) { |
| 76 | + if (auto *td = R.getAsSingle<clang::TypeDecl>()) { |
75 | 77 | if (auto *paths = R.getBasePaths(); |
76 | | - paths && R.getBasePaths()->front().Access != clang::AS_public) |
| 78 | + paths && paths->front().Access != clang::AS_public) |
77 | 79 | return nullptr; |
78 | | - |
79 | | - for (auto *nd : R) |
80 | | - if (auto *td = dyn_cast<clang::TypeDecl>(nd)) |
81 | | - return td; |
| 80 | + if (mustBeComplete && |
| 81 | + !Sema.isCompleteType({}, td->getASTContext().getTypeDeclType(td))) |
| 82 | + return nullptr; |
| 83 | + return td; |
82 | 84 | } |
83 | 85 | return nullptr; |
84 | 86 | } |
@@ -993,59 +995,66 @@ static void conformToCxxSet(ClangImporter::Implementation &impl, |
993 | 995 | bool isUniqueSet) { |
994 | 996 | PrettyStackTraceDecl trace("conforming to CxxSet", decl); |
995 | 997 | ASTContext &ctx = decl->getASTContext(); |
| 998 | + clang::Sema &clangSema = impl.getClangSema(); |
996 | 999 |
|
997 | | - auto valueType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>( |
998 | | - decl, ctx.getIdentifier("value_type")); |
999 | | - auto sizeType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>( |
1000 | | - decl, ctx.getIdentifier("size_type")); |
1001 | | - if (!valueType || !sizeType) |
| 1000 | + // Look up the type members we need from Clang |
| 1001 | + // |
| 1002 | + // N.B. we don't actually need const_iterator for multiset, but it should be |
| 1003 | + // there. If it's not there for any reason, we should probably bail out. |
| 1004 | + |
| 1005 | + auto *size_type = lookupCxxTypeMember(clangSema, clangDecl, "size_type", |
| 1006 | + /*mustBeComplete=*/true); |
| 1007 | + auto *value_type = lookupCxxTypeMember(clangSema, clangDecl, "value_type", |
| 1008 | + /*mustBeComplete=*/true); |
| 1009 | + auto *iterator = lookupCxxTypeMember(clangSema, clangDecl, "iterator", |
| 1010 | + /*mustBeComplete=*/true); |
| 1011 | + auto *const_iterator = |
| 1012 | + lookupCxxTypeMember(clangSema, clangDecl, "const_iterator", |
| 1013 | + /*mustBeComplete=*/true); |
| 1014 | + if (!size_type || !value_type || !iterator || !const_iterator) |
1002 | 1015 | return; |
1003 | 1016 |
|
1004 | | - auto insert = getInsertFunc(decl, valueType); |
1005 | | - if (!insert) |
| 1017 | + // We've looked up everything we need from Clang for the conformance. |
| 1018 | + // Now, use ClangImporter to convert those to types in Swift. |
| 1019 | + |
| 1020 | + auto *Size = dyn_cast_or_null<TypeAliasDecl>( |
| 1021 | + impl.importDecl(size_type, impl.CurrentVersion)); |
| 1022 | + auto *Value = dyn_cast_or_null<TypeAliasDecl>( |
| 1023 | + impl.importDecl(value_type, impl.CurrentVersion)); |
| 1024 | + if (!Size || !Value) |
1006 | 1025 | return; |
1007 | 1026 |
|
| 1027 | + // These are not needed for multiset, i.e., when isUniqueSet = false |
| 1028 | + TypeAliasDecl *RawMutableIterator, *RawIterator; |
| 1029 | + if (isUniqueSet) { |
| 1030 | + RawMutableIterator = dyn_cast_or_null<TypeAliasDecl>( |
| 1031 | + impl.importDecl(iterator, impl.CurrentVersion)); |
| 1032 | + RawIterator = dyn_cast_or_null<TypeAliasDecl>( |
| 1033 | + impl.importDecl(const_iterator, impl.CurrentVersion)); |
| 1034 | + if (!RawMutableIterator || !RawIterator) |
| 1035 | + return; |
| 1036 | + } |
| 1037 | + |
| 1038 | + // We have our Swift types, synthesize type aliases and conformances |
| 1039 | + |
1008 | 1040 | impl.addSynthesizedTypealias(decl, ctx.Id_Element, |
1009 | | - valueType->getUnderlyingType()); |
| 1041 | + Value->getUnderlyingType()); |
1010 | 1042 | impl.addSynthesizedTypealias(decl, ctx.Id_ArrayLiteralElement, |
1011 | | - valueType->getUnderlyingType()); |
| 1043 | + Value->getUnderlyingType()); |
1012 | 1044 | impl.addSynthesizedTypealias(decl, ctx.getIdentifier("Size"), |
1013 | | - sizeType->getUnderlyingType()); |
1014 | | - impl.addSynthesizedTypealias(decl, ctx.getIdentifier("InsertionResult"), |
1015 | | - insert->getResultInterfaceType()); |
| 1045 | + Size->getUnderlyingType()); |
| 1046 | + // The type checker can infer this from the return type of insert() |
| 1047 | + // impl.addSynthesizedTypealias(decl, ctx.getIdentifier("InsertionResult"), |
| 1048 | + // InsertionResult); |
1016 | 1049 | impl.addSynthesizedProtocolAttrs(decl, {KnownProtocolKind::CxxSet}); |
1017 | 1050 |
|
1018 | | - ProtocolDecl *cxxInputIteratorProto = |
1019 | | - ctx.getProtocol(KnownProtocolKind::UnsafeCxxInputIterator); |
1020 | | - if (!cxxInputIteratorProto) |
1021 | | - return; |
1022 | | - |
1023 | | - auto rawIteratorType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>( |
1024 | | - decl, ctx.getIdentifier("const_iterator")); |
1025 | | - auto rawMutableIteratorType = |
1026 | | - lookupDirectSingleWithoutExtensions<TypeAliasDecl>( |
1027 | | - decl, ctx.getIdentifier("iterator")); |
1028 | | - if (!rawIteratorType || !rawMutableIteratorType) |
1029 | | - return; |
1030 | | - |
1031 | | - auto rawIteratorTy = rawIteratorType->getUnderlyingType(); |
1032 | | - auto rawMutableIteratorTy = rawMutableIteratorType->getUnderlyingType(); |
1033 | | - |
1034 | | - if (!checkConformance(rawIteratorTy, cxxInputIteratorProto) || |
1035 | | - !checkConformance(rawMutableIteratorTy, cxxInputIteratorProto)) |
1036 | | - return; |
1037 | | - |
1038 | | - impl.addSynthesizedTypealias(decl, ctx.getIdentifier("RawIterator"), |
1039 | | - rawIteratorTy); |
1040 | | - impl.addSynthesizedTypealias(decl, ctx.getIdentifier("RawMutableIterator"), |
1041 | | - rawMutableIteratorTy); |
1042 | | - |
1043 | | - // Synthesize conformance to CxxUniqueSet if the caller asked for it |
1044 | | - // (if decl is std::set or std::unordered_set, but not std::multiset) |
1045 | | - if (!isUniqueSet) |
1046 | | - return; |
1047 | | - |
1048 | | - impl.addSynthesizedProtocolAttrs(decl, {KnownProtocolKind::CxxUniqueSet}); |
| 1051 | + if (isUniqueSet) { |
| 1052 | + impl.addSynthesizedTypealias(decl, ctx.getIdentifier("RawIterator"), |
| 1053 | + RawIterator->getUnderlyingType()); |
| 1054 | + impl.addSynthesizedTypealias(decl, ctx.getIdentifier("RawMutableIterator"), |
| 1055 | + RawMutableIterator->getUnderlyingType()); |
| 1056 | + impl.addSynthesizedProtocolAttrs(decl, {KnownProtocolKind::CxxUniqueSet}); |
| 1057 | + } |
1049 | 1058 | } |
1050 | 1059 |
|
1051 | 1060 | static void conformToCxxPair(ClangImporter::Implementation &impl, |
|
0 commit comments