Skip to content

Commit 1b847f3

Browse files
authored
Merge pull request swiftlang#19991 from jrose-apple/oh-node-you-didnt
[ClangImporter] Account for synthesized types when filtering by module
2 parents cc85197 + ce0ca7e commit 1b847f3

File tree

5 files changed

+104
-52
lines changed

5 files changed

+104
-52
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,72 +2011,89 @@ getClangOwningModule(ClangNode Node, const clang::ASTContext &ClangCtx) {
20112011
return nullptr;
20122012
}
20132013

2014+
static const clang::Module *
2015+
getClangTopLevelOwningModule(ClangNode Node,
2016+
const clang::ASTContext &ClangCtx) {
2017+
const clang::Module *OwningModule = getClangOwningModule(Node, ClangCtx);
2018+
if (!OwningModule)
2019+
return nullptr;
2020+
return OwningModule->getTopLevelModule();
2021+
}
2022+
20142023
static bool isVisibleFromModule(const ClangModuleUnit *ModuleFilter,
20152024
const ValueDecl *VD) {
2016-
// Include a value from module X if:
2017-
// * no particular module was requested, or
2018-
// * module X was specifically requested.
2019-
if (!ModuleFilter)
2020-
return true;
2025+
assert(ModuleFilter);
20212026

20222027
auto ContainingUnit = VD->getDeclContext()->getModuleScopeContext();
20232028
if (ModuleFilter == ContainingUnit)
20242029
return true;
20252030

2031+
// The rest of this function is looking to see if the Clang entity that
2032+
// caused VD to be imported has redeclarations in the filter module.
20262033
auto Wrapper = dyn_cast<ClangModuleUnit>(ContainingUnit);
20272034
if (!Wrapper)
20282035
return false;
20292036

20302037
auto ClangNode = VD->getClangNode();
2031-
assert(ClangNode);
2038+
if (!ClangNode) {
2039+
// If we synthesized a ValueDecl, it won't have a Clang node. But so far
2040+
// all the situations where we synthesize top-level declarations are
2041+
// situations where we don't have to worry about C redeclarations.
2042+
// We should only consider the declaration visible from its owning module.
2043+
auto *SynthesizedTypeAttr =
2044+
VD->getAttrs().getAttribute<ClangImporterSynthesizedTypeAttr>();
2045+
assert(SynthesizedTypeAttr);
2046+
2047+
// When adding new ClangImporterSynthesizedTypeAttr::Kinds, make sure that
2048+
// the above statement still holds: "we don't want to allow these
2049+
// declarations to be treated as present in multiple modules".
2050+
switch (SynthesizedTypeAttr->getKind()) {
2051+
case ClangImporterSynthesizedTypeAttr::Kind::NSErrorWrapper:
2052+
case ClangImporterSynthesizedTypeAttr::Kind::NSErrorWrapperAnon:
2053+
break;
2054+
}
20322055

2056+
return false;
2057+
}
2058+
2059+
// Macros can be "redeclared" by putting an equivalent definition in two
2060+
// different modules. (We don't actually check the equivalence.)
2061+
// FIXME: We're also not checking if the redeclaration is in /this/ module.
2062+
if (ClangNode.getAsMacro())
2063+
return true;
2064+
2065+
const clang::Decl *D = ClangNode.castAsDecl();
20332066
auto &ClangASTContext = ModuleFilter->getClangASTContext();
2034-
auto OwningClangModule = getClangOwningModule(ClangNode, ClangASTContext);
20352067

20362068
// We don't handle Clang submodules; pop everything up to the top-level
20372069
// module.
2038-
if (OwningClangModule)
2039-
OwningClangModule = OwningClangModule->getTopLevelModule();
2040-
2070+
auto OwningClangModule = getClangTopLevelOwningModule(ClangNode,
2071+
ClangASTContext);
20412072
if (OwningClangModule == ModuleFilter->getClangModule())
20422073
return true;
20432074

2044-
if (auto D = ClangNode.getAsDecl()) {
2045-
// Handle redeclared decls.
2046-
if (isa<clang::FunctionDecl>(D) || isa<clang::VarDecl>(D) ||
2047-
isa<clang::TypedefNameDecl>(D)) {
2048-
for (auto Redeclaration : D->redecls()) {
2049-
if (Redeclaration == D)
2050-
continue;
2051-
auto OwningClangModule = getClangOwningModule(Redeclaration,
2052-
ClangASTContext);
2053-
if (OwningClangModule)
2054-
OwningClangModule = OwningClangModule->getTopLevelModule();
2075+
// Handle redeclarable Clang decls by checking each redeclaration.
2076+
bool IsTagDecl = isa<clang::TagDecl>(D);
2077+
if (!(IsTagDecl || isa<clang::FunctionDecl>(D) || isa<clang::VarDecl>(D) ||
2078+
isa<clang::TypedefNameDecl>(D))) {
2079+
return false;
2080+
}
20552081

2056-
if (OwningClangModule == ModuleFilter->getClangModule())
2057-
return true;
2058-
}
2059-
} else if (isa<clang::TagDecl>(D)) {
2060-
for (auto Redeclaration : D->redecls()) {
2061-
if (Redeclaration == D)
2062-
continue;
2063-
if (!cast<clang::TagDecl>(Redeclaration)->isCompleteDefinition())
2064-
continue;
2065-
auto OwningClangModule = getClangOwningModule(Redeclaration,
2066-
ClangASTContext);
2067-
if (OwningClangModule)
2068-
OwningClangModule = OwningClangModule->getTopLevelModule();
2082+
for (auto Redeclaration : D->redecls()) {
2083+
if (Redeclaration == D)
2084+
continue;
20692085

2070-
if (OwningClangModule == ModuleFilter->getClangModule())
2071-
return true;
2072-
}
2073-
}
2074-
}
2086+
// For enums, structs, and unions, only count definitions when looking to
2087+
// see what other modules they appear in.
2088+
if (IsTagDecl)
2089+
if (!cast<clang::TagDecl>(Redeclaration)->isCompleteDefinition())
2090+
continue;
20752091

2076-
// Macros can be "redeclared" too, by putting an equivalent definition in two
2077-
// different modules.
2078-
if (ClangNode.getAsMacro())
2079-
return true;
2092+
auto OwningClangModule = getClangTopLevelOwningModule(Redeclaration,
2093+
ClangASTContext);
2094+
if (OwningClangModule == ModuleFilter->getClangModule())
2095+
return true;
2096+
}
20802097

20812098
return false;
20822099
}
@@ -2106,12 +2123,14 @@ class ClangVectorDeclConsumer : public clang::VisibleDeclConsumer {
21062123

21072124
class FilteringVisibleDeclConsumer : public swift::VisibleDeclConsumer {
21082125
swift::VisibleDeclConsumer &NextConsumer;
2109-
const ClangModuleUnit *ModuleFilter = nullptr;
2126+
const ClangModuleUnit *ModuleFilter;
21102127

21112128
public:
21122129
FilteringVisibleDeclConsumer(swift::VisibleDeclConsumer &consumer,
21132130
const ClangModuleUnit *CMU)
2114-
: NextConsumer(consumer), ModuleFilter(CMU) {}
2131+
: NextConsumer(consumer), ModuleFilter(CMU) {
2132+
assert(CMU);
2133+
}
21152134

21162135
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override {
21172136
if (isVisibleFromModule(ModuleFilter, VD))
@@ -2121,13 +2140,14 @@ class FilteringVisibleDeclConsumer : public swift::VisibleDeclConsumer {
21212140

21222141
class FilteringDeclaredDeclConsumer : public swift::VisibleDeclConsumer {
21232142
swift::VisibleDeclConsumer &NextConsumer;
2124-
const ClangModuleUnit *ModuleFilter = nullptr;
2143+
const ClangModuleUnit *ModuleFilter;
21252144

21262145
public:
21272146
FilteringDeclaredDeclConsumer(swift::VisibleDeclConsumer &consumer,
21282147
const ClangModuleUnit *CMU)
2129-
: NextConsumer(consumer),
2130-
ModuleFilter(CMU) {}
2148+
: NextConsumer(consumer), ModuleFilter(CMU) {
2149+
assert(CMU);
2150+
}
21312151

21322152
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override {
21332153
if (isDeclaredInModule(ModuleFilter, VD))
@@ -2868,10 +2888,7 @@ void ClangModuleUnit::lookupObjCMethods(
28682888
auto &clangCtx = clangSema.getASTContext();
28692889
for (auto objcMethod : objcMethods) {
28702890
// Verify that this method came from this module.
2871-
auto owningClangModule = getClangOwningModule(objcMethod, clangCtx);
2872-
if (owningClangModule)
2873-
owningClangModule = owningClangModule->getTopLevelModule();
2874-
2891+
auto owningClangModule = getClangTopLevelOwningModule(objcMethod, clangCtx);
28752892
if (owningClangModule != clangModule) continue;
28762893

28772894
// If we found a property accessor, import the property.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@import Foundation;
2+
3+
extern NSString * const SomeErrorDomain;
4+
// typedef NS_ERROR_ENUM(SomeErrorDomain, SomeErrorCode) { ... }
5+
typedef enum SomeErrorCode : long SomeErrorCode;
6+
enum __attribute__((ns_error_domain(SomeErrorDomain))) SomeErrorCode : long {
7+
SomeErrorX,
8+
SomeErrorY
9+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@import Foundation;
2+
@import Base;
3+
4+
extern NSString * const SomeErrorDomain;
5+
// typedef NS_ERROR_ENUM(SomeErrorDomain, SomeErrorCode);
6+
typedef enum SomeErrorCode : long SomeErrorCode;
7+
enum __attribute__((ns_error_domain(SomeErrorDomain))) SomeErrorCode : long;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module Base {
2+
header "Base.h"
3+
}
4+
5+
module Redeclared {
6+
header "Redeclared.h"
7+
export *
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s -verify -enable-objc-interop -I %S/Inputs/custom-modules/RedeclaredErrorEnum
2+
3+
import Redeclared
4+
5+
// Referencing this error type (defined in Base, redeclared in Redeclared)
6+
// used to cause a compiler crash (rdar://problem/45414271).
7+
_ = SomeError.self
8+
_ = SomeError.Code.self
9+
10+
_ = Redeclared.SomeError.self
11+
_ = Base.SomeError.self

0 commit comments

Comments
 (0)