Commit Graph

597 Commits

Author SHA1 Message Date
susmonteiro
51357a952c [cxx-interop] Prevent usage in Swift of C++ move constructor with default args 2025-03-07 16:02:38 +00:00
Gabor Horvath
6b24af65f0 [cxx-interop] Always import the lifetime annotations
Importing these annotations were behind the LifetimeDependence
experimental flag. However, this feature flag is intended to guard the
use of @lifetime annotations on the Swift side and lifetime inference.
The checking of imported lifetime contracts should work even when this
flag is off. Removing the flag from the importer caused some fallout.
This was mostly due to calling getInterfaceType functions before the
import of some Swift declarations were fully done so the code was
slightly improved to make decisions only based on the C++ types.
There was also a crash when on-member functions imported as methods into
Swift. That is worked around in this PR.

There is one last feature check that we cannot remove yet, we generate
@lifetime annotations in the SwiftifyImport macro.
2025-03-05 15:36:59 +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
Gábor Horváth
3b412ae0c6 Merge pull request #79697 from swiftlang/gaborh/do-not-import-nonesc-pointees
[cxx-importer] Do not import pointers to non-escapable types
2025-03-04 17:26:38 +00:00
Susana Monteiro
593f320460 Merge pull request #79325 from swiftlang/susmonteiro/copy-constructor-default-args
[cxx-interop] Prevent usage in Swift of C++ copy constructor with default args
2025-03-04 15:40:22 +00:00
Gabor Horvath
d0c167762c [cxx-importer] Do not import pointers to non-escapable types
Unfortunately, Unsafe*Pointer types do not support non-escapable
pointees so we do not really have anything to map these types to at the
moment. Previously, importing such code resulted in crashes.

rdar://145800679
2025-03-04 12:27:34 +00:00
susmonteiro
bc6573ec32 [cxx-interop] Prevent usage in Swift of C++ copy constructor with default args 2025-03-03 13:22:11 +00:00
Doug Gregor
b7b5a2a19d [SE-0458] Enable unsafe expressions / attributes / for..in effects by default
With the acceptance of SE-0458, allow the use of unsafe expressions, the
@safe and @unsafe attributes, and the `unsafe` effect on the for..in loop
in all Swift code.

Introduce the `-strict-memory-safety` flag detailed in the proposal to
enable strict memory safety checking. This enables a new class of
feature, an optional feature (that is *not* upcoming or experimental),
and which can be detected via `hasFeature(StrictMemorySafety)`.
2025-02-26 12:30:07 -08: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
fahadnayyar
9782eae585 Merge pull request #77522 from fahadnayyar/cxx-frt-inheritance-diagnostics
[cxx-interop] Infer SWIFT_SHARED_REFERENCE for types inheriting from a C++ foreign reference type
2025-02-20 13:46:28 -08:00
fahadnayyar
d8f919778d [cxx-interop] [cxx-interop] Infer SWIFT_SHARED_REFERENCE for types inheriting from a C++ foreign reference type
rdar://97914474
2025-02-20 08:46:57 -08:00
Gábor Horváth
91531554de Merge pull request #79458 from swiftlang/gaborh/unsafe-cleanup 2025-02-18 20:33:08 +00:00
John Hui
bdf22948ce [cxx-interop] Allow Swift to access non-public C++ members (#79093)
This patch introduces an a C++ class annotation, SWIFT_PRIVATE_FILEID,
which will specify where Swift extensions of that class will be allowed
to access its non-public members, e.g.:

    class SWIFT_PRIVATE_FILEID("MyModule/MyFile.swift") Foo { ... };

The goal of this feature is to help C++ developers incrementally migrate
the implementation of their C++ classes to Swift, without breaking
encapsulation and indiscriminately exposing those classes' private and
protected fields.

As an implementation detail of this feature, this patch introduces an
abstraction for file ID strings, FileIDStr, which represent a parsed pair
of module name/file name.

rdar://137764620
2025-02-18 11:22:44 -08:00
Gabor Horvath
c859557f8b [cxx-interop] Remove duplicated logic to import types as unsafe
After PR #79424 was merged the compiler proper is doing inference on
what C++ types should be considered unsafe. Remove the duplicated (and
slightly divergent) logic from the importer as we no longer need it and
we should have a consistent view of what is considered unsafe. The only
divergence left is the old logic that renames some methods to have
"Unsafe" in their names. In the future, we want to get rid of this
behavior (potentially under a new interop version).
2025-02-18 12:22:40 +00:00
Gabor Horvath
648fd43709 [cxx-interop] Remove a feature flag
SafeInterop was guarding whether we import certain foreign types as
unsafe. Since these attrbutes are only considered when an opt-in strict
language mode is on, this PR removes this feature flag. We still rely on
the presence of the AllowUnsafeAttribute flag to add the unsafe
attributes to the imported types and functions.
2025-02-17 12:37:31 +00:00
Doug Gregor
c0fb9f990a [Strict memory safety] Infer safe/unsafe for imported C types 2025-02-16 00:55:43 -08:00
Gabor Horvath
e79e04c0a6 [cxx-interop] Mark C++ reference parameters @addressable
C++ code can return values that depend on the storage that backs the
references that were passed in as argument. Thus, swift should not
introdue temporary copies of that storage before invoking those
functions as they could result in lifetime issues.
2025-02-11 11:10:51 +00:00
Gábor Horváth
40deafb285 Merge pull request #79076 from swiftlang/gaborh/zero-sized-field-import
[cxx-interop] Do not codegen zero-sized fields
2025-02-03 17:22:00 +00:00
Gabor Horvath
998591e9f9 [cxx-interop] Do not import zero-sized fields
Zero sized fields are messing up the offset calculations when we import
C++ fields to Swift. We assume that the size of the field is determined
by the type of the field. This is not true for fields marked with
no_unique_address. Those fields can have 0 size while the
sizeof(decltype(field)) is still 1.

rdar://143907490
2025-02-03 11:55:54 +00:00
John Hui
be73254cdc [cxx-interop] Import private members (#78942)
This commit removes the guardrails in ImportDecl.cpp:SwiftDeclConverter
that prevent it from importing non-public C++ members. It also
accordingly adjusts all code that assumes generated Swift decls should
be public. This commit does not import non-public inherited members;
that needs its own follow-up patch.

Note that Swift enforces stricter invariants about access levels than C++.
For instance, public typealiases cannot be assigned private underlying types,
and public functions cannot take or return private types. Meanwhile,
both of these patterns are supported in C++, where exposing private types
from a class's public interface is considered feature. As far as I am aware,
Swift was already importing such private-containing public decls from C++
already, but I added a test suite, access inversion, that checks and
documents this scenario, to ensure that it doesn't trip any assertions.
2025-01-30 14:50:15 -08:00
Gábor Horváth
109e2081b6 Merge pull request #78807 from swiftlang/gaborh/generated-ctors
[cxx-interop] Fix spurious lifetime dependence errors
2025-01-29 17:59:03 +00:00
Gabor Horvath
dd3db51f60 [cxx-interop] Make borrowing specifiers more precise
We do not need to borrow from view objects passed by value but we need
to borrow from owners taken by const reference regardless of whether it
was annotated using lifetimebound or lifetime_capture_by.
2025-01-29 11:49:32 +00:00
Doug Gregor
b3f2f00588 Suggest both @unsafe and @safe Fix-Its for unsafe types in signature 2025-01-23 07:47:19 -08:00
Gábor Horváth
795d62987f Merge pull request #78771 from swiftlang/gaborh/unsafe-lifetime-unannotated
[cxx-interop] Require lifetime annotations in safe mode
2025-01-22 18:45:26 +00:00
Gabor Horvath
b6fce85287 [cxx-interop] Fix spurious lifetime dependence errors
ClangImporter will generate value and default initializers for certain
structs imported from C++. These generated initializers have no
associated lifetime dependence information so they will trigger spurious
errors for non-escapable types. This patch makes sure these are marked
as unsafe so the type checker will not generate errors for them.
Moreover, the generated default initializer would trigger a crash for
non-escapable types as the builtin to zero initialize an object does not
support non-escapable types yet.

rdar://143040862
2025-01-22 15:34:02 +00: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
Gabor Horvath
0a38617e39 [cxx-interop] Require lifetime annotations in safe mode
In strict safe mode we should consider all C++ APIs with non-escapable
parameters unsafe unless they have their lifetimes annotated. This can
be done using [[clang::lifetimebound]], [[clang::lifetime_capture_by]],
or [[clang::noescape]].
2025-01-21 12:54:21 +00:00
Gabor Horvath
f12b48aa86 [cxx-interop] Check the safety of C++ template arguments
Swift imports template specializations as a standalone type (not as an
instantiation of a generic) so unsafety is not propagated from the
template arguments to the specialization. This PR propagates this
information explicitly.
2025-01-17 17:39:25 +00:00
Gábor Horváth
4ae5685536 Merge pull request #78544 from swiftlang/gaborh/calling-conv
[cxx-interop] Fix wrong calling convention for some C++ types
2025-01-14 10:12:29 +00:00
Egor Zhdan
18be5e862d Merge pull request #78467 from swiftlang/egorzhdan/sizeof-incomplete
[cxx-interop] Skip type metadata for C++ types that are only used in private C++ fields
2025-01-13 16:58:08 +00:00
Egor Zhdan
738c8fb6c6 [cxx-interop] Skip type metadata for C++ types that are only used in private C++ fields
This fixes compiler errors for C++ types that use pimpl idiom:
```
invalid application of 'sizeof' to an incomplete type
```

rdar://141960396
2025-01-13 12:03:35 +00:00
Doug Gregor
6ec22c2240 Fix mis-merge in test case 2025-01-10 14:44:20 -08:00
Doug Gregor
8bb5bbedbc Implement an unsafe expression to cover uses of unsafe constructs
Introduce an `unsafe` expression akin to `try` and `await` that notes
that there are unsafe constructs in the expression to the right-hand
side. Extend the effects checker to also check for unsafety along with
throwing and async operations. This will result in diagnostics like
the following:

    10 |   func sum() -> Int {
    11 |     withUnsafeBufferPointer { buffer in
    12 |       let value = buffer[0]
       |                   |     `- note: reference to unsafe subscript 'subscript(_:)'
       |                   |- warning: expression uses unsafe constructs but is not marked with 'unsafe'
       |                   `- note: reference to parameter 'buffer' involves unsafe type 'UnsafeBufferPointer<Int>'
    13 |       tryWithP(X())
    14 |       return fastAdd(buffer.baseAddress, buffer.count)

These will come with a Fix-It that inserts `unsafe` into the proper
place. There's also a warning that appears when `unsafe` doesn't cover
any unsafe code, making it easier to clean up extraneous `unsafe`.

This approach requires that `@unsafe` be present on any declaration
that involves unsafe constructs within its signature. Outside of the
signature, the `unsafe` expression is used to identify unsafe code.
2025-01-10 10:39:14 -08:00
Gabor Horvath
8cde635433 [cxx-interop] Fix wrong calling convention for some C++ types
We erroneously used @autoreleased convention for C++ types in some
scenarios.
2025-01-10 12:42:47 +00:00
Gabor Horvath
838a7547ab [cxx-interop] Consider std::string safe
The std::basic_string class is escapable only if its template argument
is escapable. This change helps us consider the regular std::string type
with the non-escapable char template argument as self-contained and a
safe type to use. This prevents spurious warnings in strict memory
safety mode.
2025-01-09 12:17:52 +00:00
Doug Gregor
70adcada23 Update test for improved strict-safety diagnostics 2024-12-20 10:25:11 -08:00
Doug Gregor
29f23bb66a Improve diagnostics for uses of unsafe declarations in functions
Instead of producing a warning for each use of an unsafe entity,
collect all of the uses of unsafe constructs within a given function
and batch them together in a single diagnostic at the function level
that tells you what you can do (add `@unsafe` or `@safe(unchecked)`,
depending on whether all unsafe uses were in the definition), plus
notes identifying every unsafe use within that declaration. The new
diagnostic renderer nicely collects together in a single snippet, so
it's easier to reason about.

Here's an example from the embedded runtime that previously would have
been 6 separate warnings, each with 1-2 notes:

```
swift/stdlib/public/core/EmbeddedRuntime.swift:397:13: warning: global function 'swift_retainCount' involves unsafe code; use '@safe(unchecked)' to assert that the code is memory-safe
395 |
396 | @_cdecl("swift_retainCount")
397 | public func swift_retainCount(object: Builtin.RawPointer) -> Int {
    |             `- warning: global function 'swift_retainCount' involves unsafe code; use '@safe(unchecked)' to assert that the code is memory-safe
398 |   if !isValidPointerForNativeRetain(object: object) { return 0 }
399 |   let o = UnsafeMutablePointer<HeapObject>(object)
    |           |                              `- note: call to unsafe initializer 'init(_:)'
    |           `- note: reference to unsafe generic struct 'UnsafeMutablePointer'
400 |   let refcount = refcountPointer(for: o)
    |                  |                    `- note: reference to let 'o' involves unsafe type 'UnsafeMutablePointer<HeapObject>'
    |                  `- note: call to global function 'refcountPointer(for:)' involves unsafe type 'UnsafeMutablePointer<Int>'
401 |   return loadAcquire(refcount) & HeapObject.refcountMask
    |          |           `- note: reference to let 'refcount' involves unsafe type 'UnsafeMutablePointer<Int>'
    |          `- note: call to global function 'loadAcquire' involves unsafe type 'UnsafeMutablePointer<Int>'
402 | }
403 |
```

Note that we have lost a little bit of information, because we no
longer produce "unsafe declaration was here" notes pointing back at
things like `UnsafeMutablePointer` or `recountPointer(for:)`. However,
strict memory safety tends to be noisy to turn on, so it's worth
losing a little bit of easily-recovered information to gain some
brevity.
2024-12-20 07:34:51 -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
Gábor Horváth
568fa14b14 Merge pull request #77617 from swiftlang/gaborh/support-lifetime-capture-by
[cxx-interop] Support lifetime_capture_by in ClangImporter
2024-12-18 13:53:16 +00:00
Gábor Horváth
4ee8e0df26 Merge pull request #78115 from swiftlang/gaborh/cpp-span-unsafe
[cxx-interop] Make sure C++ span is imported as @unsafe
2024-12-18 13:20:41 +00:00
Gabor Horvath
8399971f06 [cxx-interop] Support lifetime_capture_by in ClangImporter
Import it as lifetime dependencies.

rdar://137671377
2024-12-18 10:05:43 +00: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
Gabor Horvath
985c3a44f8 [cxx-interop] Make sure C++ span is imported as @unsafe
The C++ span should be a non-escapable type but is imported as escapable
for backward compatibility reason. This is inherently unsafe, so make
sure std::span is imported as such. In the future, we plan to generate
safe overloads using Swift's Span and that will be the preferred way of
using the API.
2024-12-16 17:11:22 +00: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
Doug Gregor
bd4a477cbd Suggest @safe(unchecked) when only the body of a declaration uses unsafe constructs
Also clean up some diagnostic text for the @unsafe/@safe(unchecked) suggestions.
2024-12-14 08:40:28 -08:00
Doug Gregor
cf7fcf2da9 Fix test and improve dumper 2024-12-12 23:03:45 -08:00
Gabor Horvath
9027edd430 [cxx-interop] Inject escapability for the C++ standard library
We only add conditional annotations because those do not break backward
compatibility (we might import span and similar view types as
non-escapable in the future). We inject these annotations in the
importer to make sure we have consistent behavior acress the different
standard library implementations. Once we can ship APINotes for the STL
and we have conditional escapability support in APINotes we can migrate
to that solution. But it is not possible as of today and Clang already
has precedent of injecting information for the STL with lifetimebound.

rdar://139065558
2024-12-05 16:27:34 +01:00
Gábor Horváth
b744793716 Merge pull request #77878 from swiftlang/gaborh/import-rval-ref
[cxx-interop] Import rvalue references as consuming parameters
2024-12-03 16:14:02 +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
Gabor Horvath
751bcfd952 [cxx-interop] Support parameter packs in escapability annotations
rdar://140271527
2024-11-22 12:32:51 +00:00