Skip to content

Commit 16f0227

Browse files
authored
Merge pull request #19991 from jrose-apple/oh-node-you-didnt (#19997)
[ClangImporter] Account for synthesized types when filtering by module (cherry picked from commit 1b847f3)
1 parent a556d39 commit 16f0227

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
@@ -2013,72 +2013,89 @@ getClangOwningModule(ClangNode Node, const clang::ASTContext &ClangCtx) {
20132013
return nullptr;
20142014
}
20152015

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

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

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

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

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

20382070
// We don't handle Clang submodules; pop everything up to the top-level
20392071
// module.
2040-
if (OwningClangModule)
2041-
OwningClangModule = OwningClangModule->getTopLevelModule();
2042-
2072+
auto OwningClangModule = getClangTopLevelOwningModule(ClangNode,
2073+
ClangASTContext);
20432074
if (OwningClangModule == ModuleFilter->getClangModule())
20442075
return true;
20452076

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

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

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

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

20832100
return false;
20842101
}
@@ -2108,12 +2125,14 @@ class ClangVectorDeclConsumer : public clang::VisibleDeclConsumer {
21082125

21092126
class FilteringVisibleDeclConsumer : public swift::VisibleDeclConsumer {
21102127
swift::VisibleDeclConsumer &NextConsumer;
2111-
const ClangModuleUnit *ModuleFilter = nullptr;
2128+
const ClangModuleUnit *ModuleFilter;
21122129

21132130
public:
21142131
FilteringVisibleDeclConsumer(swift::VisibleDeclConsumer &consumer,
21152132
const ClangModuleUnit *CMU)
2116-
: NextConsumer(consumer), ModuleFilter(CMU) {}
2133+
: NextConsumer(consumer), ModuleFilter(CMU) {
2134+
assert(CMU);
2135+
}
21172136

21182137
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override {
21192138
if (isVisibleFromModule(ModuleFilter, VD))
@@ -2123,13 +2142,14 @@ class FilteringVisibleDeclConsumer : public swift::VisibleDeclConsumer {
21232142

21242143
class FilteringDeclaredDeclConsumer : public swift::VisibleDeclConsumer {
21252144
swift::VisibleDeclConsumer &NextConsumer;
2126-
const ClangModuleUnit *ModuleFilter = nullptr;
2145+
const ClangModuleUnit *ModuleFilter;
21272146

21282147
public:
21292148
FilteringDeclaredDeclConsumer(swift::VisibleDeclConsumer &consumer,
21302149
const ClangModuleUnit *CMU)
2131-
: NextConsumer(consumer),
2132-
ModuleFilter(CMU) {}
2150+
: NextConsumer(consumer), ModuleFilter(CMU) {
2151+
assert(CMU);
2152+
}
21332153

21342154
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override {
21352155
if (isDeclaredInModule(ModuleFilter, VD))
@@ -2870,10 +2890,7 @@ void ClangModuleUnit::lookupObjCMethods(
28702890
auto &clangCtx = clangSema.getASTContext();
28712891
for (auto objcMethod : objcMethods) {
28722892
// Verify that this method came from this module.
2873-
auto owningClangModule = getClangOwningModule(objcMethod, clangCtx);
2874-
if (owningClangModule)
2875-
owningClangModule = owningClangModule->getTopLevelModule();
2876-
2893+
auto owningClangModule = getClangTopLevelOwningModule(objcMethod, clangCtx);
28772894
if (owningClangModule != clangModule) continue;
28782895

28792896
// 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)