Skip to content

Commit b4efb25

Browse files
committed
[ClangImporter] NS_ERROR_ENUMs can be redefined in separate modules
It's not something that /ought/ to happen, but when modules aren't quite set up properly (often by accident, thanks to header maps), we can get into basically this situation by having the definition end up in a header that's textually included into two different modules, or into a module and a bridging header. Handle that the same way we handle other redeclarations: have it show up in both modules. rdar://problem/45646620
1 parent e4db036 commit b4efb25

File tree

3 files changed

+37
-12
lines changed

3 files changed

+37
-12
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,7 +2021,7 @@ getClangTopLevelOwningModule(ClangNode Node,
20212021
}
20222022

20232023
static bool isVisibleFromModule(const ClangModuleUnit *ModuleFilter,
2024-
const ValueDecl *VD) {
2024+
ValueDecl *VD) {
20252025
assert(ModuleFilter);
20262026

20272027
auto ContainingUnit = VD->getDeclContext()->getModuleScopeContext();
@@ -2036,24 +2036,34 @@ static bool isVisibleFromModule(const ClangModuleUnit *ModuleFilter,
20362036

20372037
auto ClangNode = VD->getClangNode();
20382038
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.
2039+
// If we synthesized a ValueDecl, it won't have a Clang node. Find the
2040+
// associated declaration that /does/ have a Clang node, and use that.
20432041
auto *SynthesizedTypeAttr =
20442042
VD->getAttrs().getAttribute<ClangImporterSynthesizedTypeAttr>();
20452043
assert(SynthesizedTypeAttr);
20462044

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".
20502045
switch (SynthesizedTypeAttr->getKind()) {
20512046
case ClangImporterSynthesizedTypeAttr::Kind::NSErrorWrapper:
2052-
case ClangImporterSynthesizedTypeAttr::Kind::NSErrorWrapperAnon:
2047+
case ClangImporterSynthesizedTypeAttr::Kind::NSErrorWrapperAnon: {
2048+
ASTContext &Ctx = ContainingUnit->getASTContext();
2049+
auto LookupFlags =
2050+
NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
2051+
auto WrapperStruct = cast<StructDecl>(VD);
2052+
TinyPtrVector<ValueDecl *> LookupResults =
2053+
WrapperStruct->lookupDirect(Ctx.Id_Code, LookupFlags);
2054+
assert(!LookupResults.empty() && "imported error enum without Code");
2055+
2056+
auto CodeEnumIter = llvm::find_if(LookupResults,
2057+
[&](ValueDecl *Member) -> bool {
2058+
return Member->getDeclContext() == WrapperStruct;
2059+
});
2060+
assert(CodeEnumIter != LookupResults.end() &&
2061+
"could not find Code enum in wrapper struct");
2062+
assert((*CodeEnumIter)->hasClangNode());
2063+
ClangNode = (*CodeEnumIter)->getClangNode();
20532064
break;
20542065
}
2055-
2056-
return false;
2066+
}
20572067
}
20582068

20592069
// Macros can be "redeclared" by putting an equivalent definition in two
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
@import Foundation;
2+
#ifndef NO_IMPORT_BASE_FROM_REDECLARED
23
@import Base;
4+
#endif
35

46
extern NSString * const SomeErrorDomain;
57
// typedef NS_ERROR_ENUM(SomeErrorDomain, SomeErrorCode);
68
typedef enum SomeErrorCode : long SomeErrorCode;
7-
enum __attribute__((ns_error_domain(SomeErrorDomain))) SomeErrorCode : long;
9+
enum __attribute__((ns_error_domain(SomeErrorDomain))) SomeErrorCode : long
10+
#ifdef NO_IMPORT_BASE_FROM_REDECLARED
11+
{
12+
SomeErrorX,
13+
SomeErrorY
14+
}
15+
#endif
16+
;

test/ClangImporter/enum-error-redeclared.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s -verify -enable-objc-interop -I %S/Inputs/custom-modules/RedeclaredErrorEnum
2+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s -verify -enable-objc-interop -I %S/Inputs/custom-modules/RedeclaredErrorEnum -DIMPORT_BASE
3+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s -verify -enable-objc-interop -I %S/Inputs/custom-modules/RedeclaredErrorEnum -DIMPORT_BASE -Xcc -DNO_IMPORT_BASE_FROM_REDECLARED
4+
5+
#if IMPORT_BASE
6+
import Base
7+
#endif
28

39
import Redeclared
410

0 commit comments

Comments
 (0)