Files
swift-mirror/test/Interop/Cxx/modules/emit-module-interface.swift
John Hui 76a1742aca [cxx-interop] Use formal C++ interop mode to fix name lookup in module interfaces (#79984)
It is possible for a module interface (e.g., ModuleA) to be generated
with C++ interop disabled, and then rebuilt with C++ interop enabled
(e.g., because ModuleB, which imports ModuleA, has C++ interop enabled).

This circumstance can lead to various issues when name lookup behaves
differently depending on whether C++ interop is enabled, e.g., when
a module name is shadowed by a namespace of the same name---this only
happens in C++ because namespaces do not exist in C. Unfortunately,
naming namespaces the same as a module is a common C++ convention,
leading to many textual interfaces whose fully-qualified identifiers
(e.g., c_module.c_member) cannot be correctly resolved when C++ interop
is enabled (because c_module is shadowed by a namespace of the same
name).

This patch does two things. First, it introduces a new frontend flag,
-formal-cxx-interoperability-mode, which records the C++ interop mode
a module interface was originally compiled with. Doing so allows
subsequent consumers of that interface to interpret it according to the
formal C++ interop mode. Note that the actual "versioning" used by this
flag is very crude: "off" means disabled, and "swift-6" means enabled.
This is done to be compatible with C++ interop compat versioning scheme,
which seems to produce some invalid (but unused) version numbers. The
versioning scheme for both the formal and actual C++ interop modes
should be clarified and fixed in a subsequent patch.

The second thing this patch does is fix the module/namespace collision
issue in module interface files. It uses the formal C++ interop mode to
determine whether it should resolve C++-only decls during name lookup.
For now, the fix is very minimal and conservative: it only filters out
C++ namespaces during unqualified name lookup in an interface that was
originally generated without C++ interop. Doing so should fix the issue
while minimizing the chance for collateral breakge. More cases other
than C++ namespaces should be added in subsequent patches, with
sufficient testing and careful consideration.

rdar://144566922
2025-03-13 23:24:18 -07:00

22 lines
1.4 KiB
Swift

// RUN: %empty-directory(%t)
// Check if fragile Swift interface with struct extensions can be reparsed:
// RUN: %target-swift-frontend -swift-version 5 -typecheck -emit-module-interface-path %t/UsesCxxStruct.swiftinterface %s -I %S/Inputs -swift-version 5 -cxx-interoperability-mode=default %S/Inputs/namespace-extension-lib.swift
// RUN: %target-swift-frontend -swift-version 5 -typecheck-module-from-interface %t/UsesCxxStruct.swiftinterface -I %S/Inputs -cxx-interoperability-mode=default
// RUN: %FileCheck --input-file=%t/UsesCxxStruct.swiftinterface %s
// The textual module interface should not contain the C++ interop flag, but it
// should record the C++ interop version it was built with (the formal version):
// CHECK-NOT: -enable-experimental-cxx-interop
// CHECK-NOT: -cxx-interoperability-mode
// CHECK: -formal-cxx-interoperability-mode=
// Check if resilient Swift interface with builtin type extensions can be reparsed:
// RUN: %target-swift-emit-module-interface(%t/ResilientStruct.swiftinterface) %s -I %S/Inputs -enable-library-evolution -swift-version 5 -cxx-interoperability-mode=default %S/Inputs/namespace-extension-lib.swift -DRESILIENT
// RUN: %target-swift-typecheck-module-from-interface(%t/ResilientStruct.swiftinterface) -I %S/Inputs -DRESILIENT -cxx-interoperability-mode=default
// RUN: %FileCheck --input-file=%t/ResilientStruct.swiftinterface %s
import Namespaces
var x: Namespace.Parent? = nil