mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[ClangImporter] Do not import enum when already imported via DeclContext (#85424)
If we try to import this in ObjC interop mode:
```objc
typedef CF_OPTIONS(uint32_t, MyFlags) {
...
} CF_SWIFT_NAME(MyCtx.Flags);
struct MyStruct {
MyFlags flags;
...
} CF_SWIFT_NAME(MyCtx);
```
ClangImporter tries to import `MyCtx/MyStruct` before it imports
`MyFlags` (via `importDeclContextOf()`), which in turn tries to import
`MyFlags` again due to the `flags` field. The existing cycle-breaking
mechanism prevents us from looping infinitely, but leads us to import
two copies of the Swift `EnumDecl`, which can cause errors later during
CodeGen.
~~This patch adds an assertion to catch such issues earlier, and breaks
the cycle by checking the cache again.~~ This patch no longer does so
because that caused issues beyond the scope of this patch.
rdar://162317760
This commit is contained in:
@@ -1613,6 +1613,14 @@ namespace {
|
|||||||
if (!dc)
|
if (!dc)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
// It's possible that we already encountered and imported decl while
|
||||||
|
// importing its decl context. If we are able to find a cached result,
|
||||||
|
// use it to avoid making a duplicate imported decl.
|
||||||
|
auto alreadyImported =
|
||||||
|
Impl.ImportedDecls.find({decl->getCanonicalDecl(), getVersion()});
|
||||||
|
if (alreadyImported != Impl.ImportedDecls.end())
|
||||||
|
return alreadyImported->second;
|
||||||
|
|
||||||
auto name = importedName.getBaseIdentifier(Impl.SwiftContext);
|
auto name = importedName.getBaseIdentifier(Impl.SwiftContext);
|
||||||
|
|
||||||
// Create the enum declaration and record it.
|
// Create the enum declaration and record it.
|
||||||
|
|||||||
37
test/ClangImporter/circular-import-as-member.swift
Normal file
37
test/ClangImporter/circular-import-as-member.swift
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// RUN: split-file %s %t
|
||||||
|
// RUN: %target-swift-frontend -typecheck -verify -I %t/Inputs -cxx-interoperability-mode=default -module-name main %t/program.swift
|
||||||
|
// RUN: %target-swift-frontend -typecheck -verify -I %t/Inputs -cxx-interoperability-mode=off -module-name main %t/program.swift
|
||||||
|
// REQUIRES: objc_interop
|
||||||
|
|
||||||
|
//--- Inputs/module.modulemap
|
||||||
|
module TheModule {
|
||||||
|
header "the-header.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
//--- Inputs/the-header.h
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CF_SWIFT_NAME(_name) __attribute__((swift_name(#_name)))
|
||||||
|
|
||||||
|
#define __CF_OPTIONS_ATTRIBUTES __attribute__((flag_enum,enum_extensibility(open)))
|
||||||
|
#if (__cplusplus)
|
||||||
|
#define CF_OPTIONS(_type, _name) __attribute__((availability(swift,unavailable))) _type _name; enum __CF_OPTIONS_ATTRIBUTES : _name
|
||||||
|
#else
|
||||||
|
#define CF_OPTIONS(_type, _name) enum __CF_OPTIONS_ATTRIBUTES _name : _type _name; enum _name : _type
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef CF_OPTIONS(unsigned, TheFlags) {
|
||||||
|
TheFlagsFoo = (1 << 1),
|
||||||
|
TheFlagsBar = (1 << 2)
|
||||||
|
} CF_SWIFT_NAME(The.Flags);
|
||||||
|
|
||||||
|
typedef TheFlags DaFlags;
|
||||||
|
|
||||||
|
struct TheContext {
|
||||||
|
TheFlags flags;
|
||||||
|
} CF_SWIFT_NAME(The);
|
||||||
|
|
||||||
|
//--- program.swift
|
||||||
|
import TheModule
|
||||||
|
|
||||||
|
func f(_ _: DaFlags) {}
|
||||||
Reference in New Issue
Block a user