mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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
58 lines
2.4 KiB
Swift
58 lines
2.4 KiB
Swift
// RUN: %empty-directory(%t)
|
|
// RUN: %empty-directory(%t/include)
|
|
// RUN: split-file %s %t
|
|
|
|
// Generate textual interface for shim.swift without C++ interop enabled, then
|
|
// re-compile it with C++ interop enabled (because it is used by program.swift,
|
|
// which is compiled with C++ interop enabled).
|
|
//
|
|
// RUN: %empty-directory(%t/lib)
|
|
// RUN: %target-swift-emit-module-interface(%t/lib/shim.swiftinterface) %t/shim.swift -module-name shim -I %t/include
|
|
// RUN: %FileCheck %t/shim.swift < %t/lib/shim.swiftinterface
|
|
// RUN: %target-swift-frontend %t/program.swift -typecheck -verify -cxx-interoperability-mode=default -I %t/include -I %t/lib
|
|
|
|
//--- include/module.modulemap
|
|
// A Clang module which will first be compiled in C mode, and then later compiled in C++ mode
|
|
module c2cxx {
|
|
header "c2cxx.h"
|
|
export *
|
|
}
|
|
|
|
//--- include/c2cxx.h
|
|
// A header file that defines a namespace with the same name as the module,
|
|
// a common C++ idiom. We want to make sure that it does not shadow the module
|
|
// in textual interfaces generated with C++ interop disabled, but later compiled
|
|
// with C++ interop enabled.
|
|
#ifndef __C2CXX_NAMESPACE_H
|
|
#define __C2CXX_NAMESPACE_H
|
|
typedef int c2cxx_number; // always available and resilient
|
|
#ifdef __cplusplus
|
|
namespace c2cxx { typedef c2cxx_number number; }; // only available in C++
|
|
#endif // __cplusplus
|
|
#endif // __C2CXX_NAMESPACE_H
|
|
|
|
//--- shim.swift
|
|
// A shim around c2cxx that exposes a c2cxx decl in its module interface
|
|
import c2cxx
|
|
|
|
// Exposes a (fully-qualified) c2cxx decl in its module interface.
|
|
public func shimId(_ n: c2cxx_number) -> c2cxx_number { return n }
|
|
// CHECK: public func shimId(_ n: c2cxx.c2cxx_number) -> c2cxx.c2cxx_number
|
|
// ^^^^^`- refers to the module
|
|
|
|
// @inlinable functions have their bodies splatted in the module interface file;
|
|
// those verbatim bodies may contain unqualified names.
|
|
@inlinable public func shimIdInline(_ n: c2cxx_number) -> c2cxx_number {
|
|
// CHECK: public func shimIdInline(_ n: c2cxx.c2cxx_number) -> c2cxx.c2cxx_number
|
|
// ^^^^^`- refers to the module
|
|
let m: c2cxx_number = n
|
|
// CHECK: let m: c2cxx_number = n
|
|
// ^^^^^^^^^^^^`- verbatim (unqualified)
|
|
return m
|
|
}
|
|
|
|
//--- program.swift
|
|
// Uses the shim and causes it to be (re)built from its interface
|
|
import shim
|
|
func numberwang() { let _ = shimId(42) + shimIdInline(24) }
|