Explanation: We did not handle this declaration kind. This PR makes sure we
mangle it the same way we do for the target declaration.
Issue: rdar://152841420
Risk: Low, the fix is small, localized, and straightforward.
Testing: Regression test added.
Original PR: #82144
Reviewer: @egorzhdan @hnrklssn @j-hui
With the upcoming `MemberImportVisibility` feature enabled, code built with Cxx
interop also enabled could be rejected by the compiler with cryptic errors
about the `__ObjC` module not being imported. This is the result of a
surprising implementation detail of Cxx interop. When importing C++ namespaces
and their members, the Clang importer puts these declarations in the Clang
header import module (a.k.a. the bridging header module, `__ObjC`). C++
namespaces don't have a logical modular home in the Swift AST because they can
span multiple modules, so it's understandable why this implementation was
chosen. However, the concrete members of namespaces also get placed in the
`__ObjC` module too, and this really confuses things.
To work around this idiosyncrasy of Cxx interop, I've introduced
`Decl::getModuleContextForNameLookup()` which returns the module that a
declaration would ideally belong to if Cxx interop didn't have this behavior.
This alternative to `Decl::getModuleContext()` is now used everywhere that
`MemberImportVisibility` rules are enforced to provide consistency.
Additionally, I found that I also had to further special-case the header import
module for Cxx interop because it turns out that there are some additional
declarations, beyond imported namespaces, that also live there and need to be
implicitly visible in every source file. The `__ObjC` module is not implicitly
imported in source files when Cxx interop is enabled, so these declarations are
not deemed visible under normal name lookup rules. When I tried to add an
implicit import of `__ObjC` when Cxx interop is enabled, it broke a bunch
tests. So for now, when a decl really belongs to the `__ObjC` module in Cxx
interop mode, we just always allow it to be referenced.
This Cxx interop behavior really needs a re-think in my opinion, but that will
require larger discussions.
Resolves rdar://136600598.
Previously a namespace declaration was imported along with all of its redeclarations, and their members were added to a single Swift extension. This was problematic when a single namespace is declared in multiple modules – the extension belonged to only one of them.
For an example of this, try printing a module interface for `std.string`/`std.iosfwd` – it will be empty, even though the declarations from those modules are actually imported into Swift correctly.
This change makes sure that when we're importing different redeclarations of the same namespace, we're adding them as separate extensions to appropriate modules.
This fixes the issue that prevents `std::string::size_type` from being imported into Swift: `size_type` is imported before its parent struct, and we're skipping it when importing the struct afterwards.
This is caused by an out-of-line decl for `std::string::npos`:
```cpp
template<class _CharT, class _Traits, class _Allocator>
_LIBCPP_FUNC_VIS
const typename basic_string<_CharT, _Traits, _Allocator>::size_type
basic_string<_CharT, _Traits, _Allocator>::npos;
```
When importing `npos`, we first import `size_type`, which triggers the issue.
C++ namespaces are module-independent, but enums are owned by their module's in Swift. So, to prevent declaring two enums with the same name, this patch implements a new approach to namespaces: enums with extensions.
Here's an example:
```
// Module A
namespace N { void test1(); }
// Module B
namespace N { void test2(); }
// __ObjC module
enum N { }
// Swift module A
extension N { func test1() }
// Swift module B
extension N { func test1() }
```
Thanks to @gribozavr for the great idea.