Commit Graph

67 Commits

Author SHA1 Message Date
Gábor Horváth
b51b58db30 [6.2][cxx-interop] Fix unqualified name lookup failure
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
2025-07-09 17:59:11 +01:00
John Hui
c4fed45f54 [cxx-interop] Avoid unchecked recursion when importing C++ classes with circular inheritance
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)
2025-04-30 13:40:19 -07:00
Guillaume Lessard
d66fde2e47 [test] fix availability 2025-03-20 13:03:54 -07:00
susmonteiro
25efb5fc04 [cxx-interop] Disable debug info in synthesized C++ methods
rdar://141167229
2025-03-19 18:02:50 +00:00
John Hui
edc742013d [cxx-interop] Make experimental flag ImportNonPublicCxxMembers (#79728)
ClangImporter can now import non-public members as of be73254cdc and 66c2e2c52b, but doing so triggers some latent ClangImporter bugs in projects that don't use or need those non-public members.

This patch introduces a new experimental feature flag, ImportNonPublicCxxMembers, that guards against the importation of non-public members while we iron out those latent issues. Adopters of the SWIFT_PRIVATE_FILEID feature introduced in bdf22948ce can enable this flag to opt into importing private members they wish to access from Swift.

rdar://145569473
2025-03-04 13:31:46 -05:00
John Hui
66c2e2c52b [cxx-interop] Import non-public inherited members (#79348)
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
2025-02-25 01:03:16 -08:00
John Hui
1341516dba [cxx-interop] Fix spurious ambiguous member lookup for eagerly imported members (#78673)
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
2025-01-21 22:06:09 -08:00
John Hui
1e9efd4398 [cxx-interop] Fix subscript-irgen test CHECK statement (#78299)
Previously the check statement did not account for attribute groups.
This patch adds a glob at the end of the CHECK statement to allow
trailing attribute groups, and also relaxes the pattern at the
beginning.

rdar://141662805
2024-12-19 15:59:08 -08:00
John Hui
796075ab88 [cxx-interop] Fix spurious ambiguous member lookup (#78132)
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
2024-12-17 11:40:18 -08:00
Egor Zhdan
57c7ecd244 [cxx-interop] Fix memory layout for structs with out-of-order base types
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
2024-12-16 15:53:43 +00:00
Gabor Horvath
1601564342 [cxx-interop] Import rvalue references as consuming parameters
Unfortunately, importing them as is results in ambiguous call sites.
E.g., std::vector::push_back has overloads for lvalue reference and
rvalue reference and we have no way to distinguish them at the call site
in Swift. To overcome this issue, functions with rvalue reference
parameters are imported with 'consuming:' argument labels.

Note that, in general, move only types and consuming is not properly
supported in Swift yet. We do not invoke the dtor for the moved-from
objects. This is a preexisting problem that can be observed with move
only types before this PR, so the fix will be done in a separate PR.
Fortunately, for most types, the moved-from objects do not require
additional cleanups.

rdar://125816354
2024-12-02 13:09:21 +00:00
Egor Zhdan
6943986c71 [cxx-interop] Import private fields of C++ structs
While private and protected fields coming from C++ cannot be accessed from Swift, they can affect Swift typechecking.

For instance, the Swift typechecker mechanism that adds implicit `Sendable` conformances works by iterating over all of the struct's fields and checking whether all of them are `Sendable`. This logic was broken for C++ types with private fields, since they were never accounted for. This resulted in erroneous implicit `Sendable` confromances being added.

Same applies for `BitwiseCopyable`.

In addition to this, ClangImporter used to mistakenly mark all C++ structs that have private fields as types with unreferenceable storage, which hampered optimizations.

As a side effect of this change, we now also provide a better diagnostic when someone tries to access a private C++ field from Swift.

rdar://134430857
2024-11-12 12:47:26 +00:00
Egor Zhdan
d3e43bbe7b [cxx-interop] Fix IRGen for C++ types that use tail padding of their bases
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
2024-11-04 13:44:43 +00:00
John Hui
b58a908082 [cxx-interop] Add Hashable conformance to imported enums (#76940)
* [cxx-interop] Add Hashable conformance to imported enums

Previously, imported enums only conformed to RawRepresentable and Equatable,
so they could not be used as members of a Set or keys of a Dictionary.
This patch adds Hashable conformance to give them that ability,
as well as some test cases to clarify the expected behavior.
Existing test cases are updated to reflect this new conformance.

rdar://129713687
2024-10-15 20:24:35 -07:00
Akira Hatanaka
380f319371 Relax check strings (#76421)
rdar://135165028
2024-09-12 10:35:36 -07:00
Akira Hatanaka
7aaed1efea Pass --dump-input-filter=all to debug failing test (#76333) 2024-09-09 10:47:31 -07:00
Akira Hatanaka
f81d2e67f7 Fix a test that was failing on armv7k (#76259)
rdar://135165028
2024-09-04 17:06:20 -07:00
Akira Hatanaka
7cdbb64567 Disable test on arm64e (#76229)
rdar://135165028
2024-09-03 19:51:32 -07:00
Akira Hatanaka
5bd7a27e96 [cxx-interop] Do not over-release objects returned by synthesized C++ methods (#76139)
Call Sema::BuildReturnStmt instead of ReturnStmt::Create so that an
implicit cast of kind ARCProduceObject is inserted in the AST.

rdar://133731973
2024-08-29 20:45:16 -07:00
Gabor Horvath
ce3fa734ce [cxx-interop] Fix wrong field offsets with value types using inheritance
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
2024-07-11 17:20:18 +01:00
Egor Zhdan
b50955144e [cxx-interop] Clone all of the attributes from base method correctly
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.
2024-07-08 15:48:20 +01:00
Egor Zhdan
b330376a43 [cxx-interop] Pull changes from swift-6 compat mode into swift-5.9
This gives projects using C++ interop compat mode 5.9 access to the new features such as virtual methods and move-only types.

rdar://126485814
2024-04-24 11:53:31 +01:00
Egor Zhdan
5fce3f9d5b Merge pull request #71715 from eltociear/patch-50
Fix typo in runtime-polymorphism.swift
2024-04-22 12:36:41 +02:00
Egor Zhdan
b19ca43a43 [cxx-interop] Fix virtual method tests on non-macOS 2024-03-03 00:49:45 +00:00
Egor Zhdan
8ead7224b7 [cxx-interop] Overhaul virtual method support
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
2024-03-01 19:45:58 +00:00
Egor Zhdan
78b9de1391 [cxx-interop] Run tests with swift-6 compat mode 2024-02-23 16:24:14 +00:00
Alex Lorenz
6312fc05cc [interop] adopt a swift-6 interoperability mode for new features in the next release 2024-02-21 09:27:45 -08:00
Ikko Eltociear Ashimine
0c1ffb1a21 Fix typo in runtime-polymorphism.swift
comparision -> comparison
2024-02-19 00:49:30 +09:00
Egor Zhdan
233b80e431 Merge pull request #70503 from apple/egorzhdan/no-abstract-ctors
[cxx-interop] Do not import constructors of abstract C++ classes
2023-12-18 17:24:00 +00:00
Egor Zhdan
325868808b [cxx-interop] Do not import constructors of abstract C++ classes
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
2023-12-18 14:52:32 +00:00
Alex Lorenz
9261fa765d Merge pull request #70420 from hyp/eng/virtual-methods++
[cxx-interop] virtual method fixes
2023-12-16 06:37:44 -08:00
Egor Zhdan
73cf3be98c [cxx-interop] Do not import CxxShim explicitly in tests 2023-12-15 19:51:41 +00:00
Alex Lorenz
72db47239b [cxx-interop] enable the virtual methods irgen test on windows 2023-12-13 14:33:09 -08:00
Alex Lorenz
c19ea96809 [interop] allow virtual methods only for the 'upcoming-swift' release 2023-12-12 17:20:53 -08:00
Puyan Lotfi
128064f31d [cxx-interop] Enable virtual function calling from Swift to C++
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.
2023-12-04 01:55:30 -05:00
Egor Zhdan
efc008a2ca [cxx-interop] Import using decls that expose methods from private base classes
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
2023-11-14 00:30:54 +00:00
Egor Zhdan
f9bf957594 [cxx-interop] Do not import inherited methods with rvalue this
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
2023-11-09 13:42:59 +00:00
Egor Zhdan
879b04f2e7 Merge pull request #69327 from apple/egorzhdan/circular-requests
[cxx-interop] Avoid circular reference errors when importing C++ structs
2023-10-23 14:35:02 +01:00
Egor Zhdan
4632d894e6 [cxx-interop] Avoid circular reference errors when importing C++ structs
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
2023-10-23 12:19:05 +01:00
Alex Lorenz
be24516f85 [cxx-interop] Fix test failures after https://github.com/apple/swift/pull/68846
rdar://117205273
2023-10-19 12:33:24 -07:00
Alex Lorenz
41dc466108 Merge pull request #68846 from hyp/eng/base-member-cxx-synthesized-accessor
[cxx-interop] Use a synthesized C++ method when invoking a base metho…
2023-10-17 07:07:59 -07:00
Alex Lorenz
415045024c [cxx-interop] Use a synthesized C++ method when accessing a base field or subscript from a derived class synthesized method
The use of a synthesized C++ method allows us to avoid making a copy of self when accessing the base field or subscript from Swift
2023-10-16 14:34:37 -07:00
Egor Zhdan
041005af7c [cxx-interop] Use more correct type names in C++ template parameters
When importing a C++ class template instantiation, Swift translates the template parameter type names from C++ into their Swift equivalent.

For instance, `basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>>` gets imported as `basic_string<Scalar, char_traits<Scalar>, allocator<Scalar>>`: `wchar_t` is imported as `CWideChar`, which is a typealias for `Scalar` on most platforms including Darwin. Notice that Swift goes through the `CWideChar` typealias on the specific platform. Another instantiation `basic_string<uint32_t, char_traits<uint32_t>, allocator<uint32_t>>` also gets imported as `basic_string<Scalar, char_traits<Scalar>, allocator<Scalar>>`: `uint32_t` is also imported as `Scalar`. This is problematic because we have two distinct C++ types that have the same name in Swift.

This change makes sure Swift doesn't go through typealiases when emitting names of template parameters, so `wchar_t` would now get printed as `CWideChar`, `int` would get printed as `CInt`, etc.

This also encourages clients to use the correct type (`CInt`, `CWideChar`, etc) instead of relying on platform-specific typealiases.

rdar://115673622
2023-10-09 14:57:10 +01:00
Alex Lorenz
ba5b1bab89 [cxx-interop] Use a synthesized C++ method when invoking a base method from a derived class synthesized method
The use of a synthesized C++ method allows us to avoid making a copy of self when invoking the base method from Swift
2023-09-29 13:52:10 -07:00
Egor Zhdan
c2f6cc6e05 [cxx-interop] Update an inheritance test
`__swift_interopStaticCast` is now defined in the CxxShim module. Clients do not need to redefine it manually.
2023-08-23 18:45:52 +01:00
Alex Lorenz
96806f4d44 [cxx-interop] Windows: unify address-only logic and mark non-trivial loadable C++ types as unavailable
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.
2023-07-20 14:58:02 -07:00
Alex Lorenz
a10332548c [cxx-interop] Do not add base class members that cause lookup ambiguities with a derived class member of the same name
Fixes https://github.com/apple/swift/issues/66323
2023-07-07 10:38:48 -07:00
Alex Lorenz
c2315060b6 [interop] mark C++ virtual functions as unavailable in Swift
They're not yet supported
2023-04-10 11:51:38 -07:00
Egor Zhdan
9e35a175e9 [cxx-interop] Members of private base classes should not be exposed
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
2023-01-04 13:41:50 +00:00
Mike Pinkerton
742d47893d Failing tests for runtime polymorphism. 2022-12-15 16:14:13 -05:00