Skip to content

Commit c4d1535

Browse files
committed
[cxx-interop] Use clang lookups for std::set conformance
1 parent 6ed9efb commit c4d1535

File tree

1 file changed

+60
-51
lines changed

1 file changed

+60
-51
lines changed

lib/ClangImporter/ClangDerivedConformances.cpp

Lines changed: 60 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
#include "swift/AST/ProtocolConformance.h"
1919
#include "swift/Basic/Assertions.h"
2020
#include "swift/ClangImporter/ClangImporterRequests.h"
21+
#include "clang/AST/ASTContext.h"
2122
#include "clang/AST/CXXInheritance.h"
23+
#include "clang/AST/Decl.h"
24+
#include "clang/AST/DeclCXX.h"
2225
#include "clang/Sema/DelayedDiagnostic.h"
2326
#include "clang/Sema/Lookup.h"
2427
#include "clang/Sema/Overload.h"
@@ -62,23 +65,22 @@ static CxxStdType identifyCxxStdTypeByName(StringRef name) {
6265

6366
static const clang::TypeDecl *
6467
lookupCxxTypeMember(clang::Sema &Sema, const clang::CXXRecordDecl *Rec,
65-
StringRef name) {
68+
StringRef name, bool mustBeComplete = false) {
6669
auto R = clang::LookupResult(Sema, &Sema.PP.getIdentifierTable().get(name),
6770
clang::SourceLocation(),
6871
clang::Sema::LookupMemberName);
6972
R.suppressDiagnostics();
70-
7173
auto *Ctx = static_cast<const clang::DeclContext *>(Rec);
7274
Sema.LookupQualifiedName(R, const_cast<clang::DeclContext *>(Ctx));
7375

74-
if (R.isSingleResult()) {
76+
if (auto *td = R.getAsSingle<clang::TypeDecl>()) {
7577
if (auto *paths = R.getBasePaths();
76-
paths && R.getBasePaths()->front().Access != clang::AS_public)
78+
paths && paths->front().Access != clang::AS_public)
7779
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;
8284
}
8385
return nullptr;
8486
}
@@ -993,59 +995,66 @@ static void conformToCxxSet(ClangImporter::Implementation &impl,
993995
bool isUniqueSet) {
994996
PrettyStackTraceDecl trace("conforming to CxxSet", decl);
995997
ASTContext &ctx = decl->getASTContext();
998+
clang::Sema &clangSema = impl.getClangSema();
996999

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)
10021015
return;
10031016

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)
10061025
return;
10071026

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+
10081040
impl.addSynthesizedTypealias(decl, ctx.Id_Element,
1009-
valueType->getUnderlyingType());
1041+
Value->getUnderlyingType());
10101042
impl.addSynthesizedTypealias(decl, ctx.Id_ArrayLiteralElement,
1011-
valueType->getUnderlyingType());
1043+
Value->getUnderlyingType());
10121044
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);
10161049
impl.addSynthesizedProtocolAttrs(decl, {KnownProtocolKind::CxxSet});
10171050

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+
}
10491058
}
10501059

10511060
static void conformToCxxPair(ClangImporter::Implementation &impl,

0 commit comments

Comments
 (0)