Explanation: C++ interop synthesizes certain forwarding functions in an
_ObjC module. This confuses MemberImportVisibility. This patch adds
logic to work this around by keeping a mapping between the synthesized
and the original function and looks up where the synthesized functions
belong to based on the original functions' parent module.
Scope: C++ forward interop when MemberImportVisibility is enabled.
Issues: rdar://154887575
Original PRs: #82840
Risk: Low, a narrow change makes getModuleContextForNameLookupForCxxDecl more
precise, and it is only used with MemberImportVisibility.
Testing: Added a compiler test.
Reviewers: @egorzhdan, @tshortli, @hnrklssn
It is possible for a C++ class template to inherit from a specialization
of itself. Normally, these are imported to Swift as separate (unrelated)
types, but when symbolic import is enabled, unspecialized templates are
imported in place of their specializations, leading to circularly
inheriting classes to seemingly inherit from themselves.
This patch adds a check to guard against the most common case of
circular inheritance, when a class template directly inherits from
itself. This pattern appears in a recent version of libc++,
necessitating this patch. However, the solution here is imperfect as it
does not handle more complex/contrived circular inheritance patterns.
This patch also adds a test case exercising this pattern. The
-index-store-path flag causes swift-frontend to index the C++ module
with symbolic import enabled, without the fix in this patch, that test
triggers an assertion failure due to the circular reference (and can
infinitely recurse in the StorageVisitor when assertions are disabled).
rdar://148026461
(cherry picked from commit 1f2107f357)
This patch is follow-up work from #78942 and imports non-public members,
which were previously not being imported. Those members can be accessed
in a Swift file blessed by the SWIFT_PRIVATE_FILEID annotation.
As a consequence of this patch, we are also now importing inherited members
that are inaccessible from the derived classes, because they were declared
private, or because they were inherited via nested private inheritance. We
import them anyway but mark them unavailable, for better diagnostics and to
(somewhat) simplify the import logic for inheritance.
Because non-public base class members are now imported too, this patch
inflames an existing issue where a 'using' declaration on an inherited member
with a synthesized name (e.g., operators) produces duplicate members, leading
to miscompilation (resulting in a runtime crash). This was not previously noticed
because a 'using' declaration on a public inherited member is not usually
necessary, but is a common way to expose otherwise non-public members.
This patch puts in a workaround to prevent this from affecting the behavior
of MSVC's std::optional implementation, which uses this pattern of 'using'
a private inherited member. That will be fixed in a follow-up patch.
Follow-up work is also needed to correctly diagnose ambiguous overloads
in cases of multiple inheritance, and to account for virtual inheritance.
rdar://137764620
Follow-up from #78132, which did not fix issues related to eagerly imported members like subscripts.
This patch restructures recursive ClangRecordMemberLookup requests to importBaseMemberDecl() in the recursive calls, rather than propagating base member decls up to the initial lookup request and doing the import. Doing so seems to fix lingering resolution issues (which I've added to the regression tests).
rdar://141069984
Nested calls to importBaseMemberDecl() subvert its cache and compromise its idempotence, causing the semantic checker to spuriously report ambiguous member lookups when multiple ClangRecordMemberLookup requests are made (e.g., because of an unrelated missing member lookup).
One such scenario is documented as a test case: test/Interop/Cxx/class/inheritance/inherited-lookup-typechecker.swift fails without this patch because of the expected error from the missing member. Meanwhile, test/Interop/Cxx/class/inheritance/inherited-lookup-executable.swift works because it does not attempt to access a missing member.
This patch fixes the issue by only calling importBaseMemberDecl() in the most derived class (where the ClangRecordMemberLookup originated, i.e., not in recursive requests).
As a consequence of my patch, synthesized member accessors in the derived class directly invoke the member from the base class where the member is inherited from, rather than incurring an indirection at each level of inheritance. As such, the synthesized symbol names are different (and shorter). I've taken this opportunity to update the relevant tests to // CHECK for more of the mangled symbol, rather than only the synthesized symbol prefix, for more precise testing and slightly better readability.
rdar://141069984
In C++, a primary base class that is placed in the beginning of the type's memory layout isn't always the type that is the first in the list of bases – the base types might be laid out in memory in a different order.
This makes sure that IRGen handles base types of C++ structs in the correct order.
This fixes an assertion in asserts-enabled compilers, and an out-of-memory error in asserts-disabled compilers. The issue was happening for both value types and foreign reference types. This change also includes a small refactoring to reuse the logic between the two code paths.
rdar://140848603
In C++, a field of a derived class might be placed into the tail padding of a base class. Swift was not handling this case correctly, causing an asserts-disabled compiler to run out of RAM, and an asserts-enabled compiler to fail with an assertion.
Fixes this IRGen assertion:
```
Assertion failed: (offset >= NextOffset && "adding fields out of order"), function addField, file GenStruct.cpp, line 1509.
```
rdar://138764929
Instead of adding opaque fields for the base subobjects this patch
introduces a recursive walk to add all the base fields to the generated
Swift struct.
rdar://126754931
If a C++ `struct Base` declares a method with a Clang attribute that Swift is able to import, and `struct Derived` inherits from `Base`, the method should get cloned from `Base` to `Derived` with its attributes.
Previously we were only cloning one attribute at most due to a bug in `cloneImportedAttributes`. DeclAttributes is an intrusively linked list, and it was being made invalid while iterating over it: `otherDecl->getAttrs().add(attrs)` iterates over the list and calls `otherDecl->add(eachElement)`, which invalidates the iterator after the first iteration.
This adds a new implementation of virtual method dispatch that handles reference types correctly.
Previously, for all C++ types an invocation of a virtual method would actually get dispatched statically. For value types this is expected and matches what C++ does because of slicing. For reference types, however, this is incorrect, we should do dynamic dispatch.
rdar://123852577
Clang rejects code that tries to call a constructor of an abstract C++ class with an error: "Variable type 'Base' is an abstract class". Swift should reject this as well.
rdar://119689243
This is a forward-interop feature that wires up existing functionality for
synthesizing base class function calling to enable virtual function calling.
The general idea is to sythesize the pattern:
```
// C++ class:
struct S { virtual auto f() -> int { return 42; } };
// Swift User:
var s = S()
print("42: \(s.f())")
// Synthetized Swift Code:
extension S { func f() -> CInt { __synthesizedVirtualCall_f() } }
// Synthetized C/C++ Code:
auto __cxxVirtualCall_f(S *s) -> int { return s->f(); }
```
The idea here is to allow for the synthetized C++ bits from the Clang side to
handle the complexity of virtual function calling.
If a C++ type `Derived` inherits from `Base` privately, the public methods from `Base` should not be callable on an instance of `Derived`. However, C++ supports exposing such methods via a using declaration: `using MyPrivateBase::myPublicMethod;`.
MSVC started using this feature for `std::optional` which means Swift doesn't correctly import `var pointee: Pointee` for instantiations of `std::optional` on Windows. This prevents the automatic conformance to `CxxOptional` from being synthesized.
rdar://114282353 / resolves https://github.com/apple/swift/issues/68068
We do not synthesize the inheritance thunks correctly for such methods. Do not try to synthesize them, as that causes issues when there are two overloads of the same method, one with rvalue this and one without.
The proper solution is tracked as https://github.com/apple/swift/issues/69745
Unblocks rdar://114282353
When importing a C++ struct, if its owning module requires cplusplus, Swift tried to auto-conform it to certain protocols from the Cxx module. This triggers name lookup in the clang struct, specifically for `__beginUnsafe()` and `__endUnsafe` methods, which imports all of the base structs including their methods.
This moves the import of base structs out of the name lookup request, preventing cycles.
rdar://116426238
Windows logic for determining address-only type layout for a C++ type is now unified with other platforms.
However, this means that on Windows, a C++ type with a custom destructor, but a default copy constructor
is now loadable, even though it's non-trivial. Since Swift does not support such type operations at the
moment (it can't be yet destroyed), mark such type as unavailable in Swift instead, when building for
the Windows target.
This fixes the Windows miscompilation related to such types when they were passed indirectly to C++
functions even though they're actually passed directly.
Trying to use members of C++ private base classes from Swift causes an assertion failure in ClangImporter:
```
<build dir>/swift/lib/swift/macosx/arm64/libcxxshim.h:2:66: error: cannot cast 'A' to its private base class 'B'
To __swift_interopStaticCast(From from) { return static_cast<To>(from); }
^
```
Such members should not be exposed.
rdar://103871000
Even if a virtual method is not used directly from Swift, it might get emitted into the vtable, and in that case the IR for it should be emitted to avoid linker errors.
Fixes https://github.com/apple/swift/issues/61730.
This commit adds very basic support for importing and calling base class methods, getting and setting base class fields, and using types inside of base classes.