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