Skip to content

Commit 925f291

Browse files
committed
[ClangImporter] Add direct access for import-as-member types.
This avoids having to bring in all members (and extensions!) for an outer type just to look up a nested type. In the test case attached (reduced from the project in SR-5284), this actually led to a circular dependency between deserialization and the importer, which resulted in a compiler crash. This is not a new problem, but it's more important with the release of Swift 4, where a number of Apple SDK types are now newly imported as member types. (The one in the original bug was NSView.AutoresizingMask, formerly NSAutoresizingMaskOptions.) Since we always use the Swift 4 name for cross-references, this affected everyone, even those still compiling in Swift 3 mode. https://bugs.swift.org/browse/SR-5284
1 parent 03e1e3b commit 925f291

File tree

6 files changed

+106
-3
lines changed

6 files changed

+106
-3
lines changed

include/swift/ClangImporter/ClangModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ class ClangModuleUnit final : public LoadedFile {
6262
DeclName name, NLKind lookupKind,
6363
SmallVectorImpl<ValueDecl*> &results) const override;
6464

65+
virtual TypeDecl *
66+
lookupNestedType(Identifier name,
67+
const NominalTypeDecl *baseType) const override;
68+
6569
virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath,
6670
VisibleDeclConsumer &consumer,
6771
NLKind lookupKind) const override;

lib/ClangImporter/ClangImporter.cpp

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2432,6 +2432,70 @@ static bool isVisibleClangEntry(clang::ASTContext &ctx,
24322432
return true;
24332433
}
24342434

2435+
TypeDecl *
2436+
ClangModuleUnit::lookupNestedType(Identifier name,
2437+
const NominalTypeDecl *baseType) const {
2438+
auto lookupTable = owner.findLookupTable(clangModule);
2439+
if (!lookupTable)
2440+
return nullptr;
2441+
2442+
auto baseTypeContext = owner.getEffectiveClangContext(baseType);
2443+
if (!baseTypeContext)
2444+
return nullptr;
2445+
2446+
auto &clangCtx = owner.getClangASTContext();
2447+
2448+
// FIXME: This is very similar to what's in Implementation::lookupValue and
2449+
// Implementation::loadAllMembers.
2450+
SmallVector<TypeDecl *, 2> results;
2451+
for (auto entry : lookupTable->lookup(SerializedSwiftName(name.str()),
2452+
baseTypeContext)) {
2453+
// If the entry is not visible, skip it.
2454+
if (!isVisibleClangEntry(clangCtx, entry)) continue;
2455+
2456+
auto clangDecl = entry.dyn_cast<clang::NamedDecl *>();
2457+
auto clangTypeDecl = dyn_cast_or_null<clang::TypeDecl>(clangDecl);
2458+
if (!clangTypeDecl)
2459+
continue;
2460+
2461+
clangTypeDecl = cast<clang::TypeDecl>(clangTypeDecl->getMostRecentDecl());
2462+
2463+
bool anyMatching = false;
2464+
TypeDecl *originalDecl = nullptr;
2465+
owner.forEachDistinctName(clangTypeDecl, [&](ImportedName newName,
2466+
ImportNameVersion nameVersion){
2467+
if (anyMatching)
2468+
return;
2469+
if (!newName.getDeclName().isSimpleName(name))
2470+
return;
2471+
2472+
auto decl = dyn_cast_or_null<TypeDecl>(
2473+
owner.importDeclReal(clangTypeDecl, nameVersion));
2474+
if (!decl)
2475+
return;
2476+
2477+
if (!originalDecl)
2478+
originalDecl = decl;
2479+
else if (originalDecl == decl)
2480+
return;
2481+
2482+
auto *importedContext = decl->getDeclContext()->
2483+
getAsNominalTypeOrNominalTypeExtensionContext();
2484+
if (importedContext != baseType)
2485+
return;
2486+
2487+
assert(decl->getFullName().matchesRef(name) &&
2488+
"importFullName behaved differently from importDecl");
2489+
results.push_back(decl);
2490+
anyMatching = true;
2491+
});
2492+
}
2493+
2494+
if (results.size() == 1)
2495+
return results.front();
2496+
return nullptr;
2497+
}
2498+
24352499
void ClangImporter::loadExtensions(NominalTypeDecl *nominal,
24362500
unsigned previousGeneration) {
24372501
// Determine the effective Clang context for this Swift nominal type.
@@ -3127,7 +3191,7 @@ void ClangImporter::Implementation::lookupAllObjCMembers(
31273191
}
31283192

31293193
EffectiveClangContext ClangImporter::Implementation::getEffectiveClangContext(
3130-
NominalTypeDecl *nominal) {
3194+
const NominalTypeDecl *nominal) {
31313195
// If we have a Clang declaration, look at it to determine the
31323196
// effective Clang context.
31333197
if (auto constClangDecl = nominal->getClangDecl()) {
@@ -3142,7 +3206,7 @@ EffectiveClangContext ClangImporter::Implementation::getEffectiveClangContext(
31423206

31433207
// Resolve the type.
31443208
if (auto typeResolver = getTypeResolver())
3145-
typeResolver->resolveDeclSignature(nominal);
3209+
typeResolver->resolveDeclSignature(const_cast<NominalTypeDecl *>(nominal));
31463210

31473211
// If it's an @objc entity, go look for it.
31483212
if (nominal->isObjC()) {

lib/ClangImporter/ImporterImpl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1180,7 +1180,8 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
11801180
VisibleDeclConsumer &consumer);
11811181

11821182
/// Determine the effective Clang context for the given Swift nominal type.
1183-
EffectiveClangContext getEffectiveClangContext(NominalTypeDecl *nominal);
1183+
EffectiveClangContext
1184+
getEffectiveClangContext(const NominalTypeDecl *nominal);
11841185

11851186
/// Attempts to import the name of \p decl with each possible
11861187
/// ImportNameVersion. \p action will be called with each unique name.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
struct Outer {
2+
int value;
3+
};
4+
5+
struct __attribute__((swift_name("Outer.InterestingValue"))) Inner {
6+
int value;
7+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module NestedClangTypes {
2+
header "NestedClangTypes.h"
3+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend -emit-module -o %t -I %S/Inputs/xref-nested-clang-type/ %s -module-name Lib
4+
5+
// RUN: %target-swift-frontend -typecheck -I %t -I %S/Inputs/xref-nested-clang-type/ %s -DCLIENT -verify
6+
7+
#if CLIENT
8+
9+
import Lib
10+
11+
func test(x: MyInner) {}
12+
13+
#else
14+
15+
import NestedClangTypes
16+
17+
public typealias MyOuter = Outer
18+
public typealias MyInner = Outer.InterestingValue
19+
20+
extension MyOuter {
21+
public func use(inner: MyInner) {}
22+
}
23+
24+
#endif

0 commit comments

Comments
 (0)