Skip to content

Commit c74abe0

Browse files
authored
[ClangImporter] NS_ERROR_ENUMs can be redefined in separate modules (#20572)
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 (cherry picked from commit 647dd40)
2 parents d7a416d + 456897c commit c74abe0

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
@@ -2025,7 +2025,7 @@ getClangTopLevelOwningModule(ClangNode Node,
20252025
}
20262026

20272027
static bool isVisibleFromModule(const ClangModuleUnit *ModuleFilter,
2028-
const ValueDecl *VD) {
2028+
ValueDecl *VD) {
20292029
assert(ModuleFilter);
20302030

20312031
auto ContainingUnit = VD->getDeclContext()->getModuleScopeContext();
@@ -2040,24 +2040,34 @@ static bool isVisibleFromModule(const ClangModuleUnit *ModuleFilter,
20402040

20412041
auto ClangNode = VD->getClangNode();
20422042
if (!ClangNode) {
2043-
// If we synthesized a ValueDecl, it won't have a Clang node. But so far
2044-
// all the situations where we synthesize top-level declarations are
2045-
// situations where we don't have to worry about C redeclarations.
2046-
// We should only consider the declaration visible from its owning module.
2043+
// If we synthesized a ValueDecl, it won't have a Clang node. Find the
2044+
// associated declaration that /does/ have a Clang node, and use that.
20472045
auto *SynthesizedTypeAttr =
20482046
VD->getAttrs().getAttribute<ClangImporterSynthesizedTypeAttr>();
20492047
assert(SynthesizedTypeAttr);
20502048

2051-
// When adding new ClangImporterSynthesizedTypeAttr::Kinds, make sure that
2052-
// the above statement still holds: "we don't want to allow these
2053-
// declarations to be treated as present in multiple modules".
20542049
switch (SynthesizedTypeAttr->getKind()) {
20552050
case ClangImporterSynthesizedTypeAttr::Kind::NSErrorWrapper:
2056-
case ClangImporterSynthesizedTypeAttr::Kind::NSErrorWrapperAnon:
2051+
case ClangImporterSynthesizedTypeAttr::Kind::NSErrorWrapperAnon: {
2052+
ASTContext &Ctx = ContainingUnit->getASTContext();
2053+
auto LookupFlags =
2054+
NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
2055+
auto WrapperStruct = cast<StructDecl>(VD);
2056+
TinyPtrVector<ValueDecl *> LookupResults =
2057+
WrapperStruct->lookupDirect(Ctx.Id_Code, LookupFlags);
2058+
assert(!LookupResults.empty() && "imported error enum without Code");
2059+
2060+
auto CodeEnumIter = llvm::find_if(LookupResults,
2061+
[&](ValueDecl *Member) -> bool {
2062+
return Member->getDeclContext() == WrapperStruct;
2063+
});
2064+
assert(CodeEnumIter != LookupResults.end() &&
2065+
"could not find Code enum in wrapper struct");
2066+
assert((*CodeEnumIter)->hasClangNode());
2067+
ClangNode = (*CodeEnumIter)->getClangNode();
20572068
break;
20582069
}
2059-
2060-
return false;
2070+
}
20612071
}
20622072

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