Skip to content

Commit 080b3a3

Browse files
committed
[cxx-interop] Remove UnsafeLifetimeOperation record semantic kind.
This makes "owned" the default kind for records that have custom copy constructors and no pointer-members.
1 parent 955687f commit 080b3a3

File tree

6 files changed

+16
-38
lines changed

6 files changed

+16
-38
lines changed
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
11
# C++ Interop User Manual
22

3+
The following document explains how C++ APIs are imported into Swift and is targeted at users of C++ interoperability. Hopefully this document will help you understand why the compiler cannot import various APIs and help you update these APIs to be useable from Swift. First, the document will lay out some API patterns and definitions, then it will discuss how the Swift compiler decides if an API should be usable in Swift.
4+
35
## Reference Types
46

57
Reference types have reference semantics and object identity. A reference type is a pointer (or “reference”) to some object which means there is a layer of indirection. When a reference type is copied, the pointer’s value is copied rather than the object’s storage. This means reference types can be used to represent non-copyable types in C++. Any C++ APIs that use reference types must have at least one layer of indirection to the type (a pointer or reference). Currently reference types must be immortal (never deallocated) or have manually managed lifetimes. You can specify a type has reference semantics by using the `import_reference` swift attribute.
68

79
## Owned Types
810

9-
Owned types “own” some storage which can be copied and destroyed. An owned type must be copyable and destructible. The copy constructor must copy any storage that is owned by the type and the destructor must destroy that storage. Copies and destroys must balance out and these operations must not have side effects. Examples of owned types include `std::vector` and `std::string`. You can specify a type is an owned type by using the `import_owned` swift attribute.
11+
Owned types “own” some storage which can be copied and destroyed. An owned type must be copyable and destructible. The copy constructor must copy any storage that is owned by the type and the destructor must destroy that storage. Copies and destroys must balance out and these operations must not have side effects. Examples of owned types include `std::vector` and `std::string`. The Swift compiler will assume that any types which do not contain pointers are owned types. You can also specify a type is an owned type by using the `import_owned` swift attribute.
1012

1113
## Iterator Types
1214

13-
An iterator represents a point in a range. Iterator types must provide a comparison operator and increment operator (increment or ++ operators are imported as a member called successor). Iterators can be returned by `begin` and `end` methods to form a range which will automatically be imported as a Sequence in Swift. Iterators can often be inferred by the compiler, but you can also specify a type is an iterator by using the `import_iterator` swift attribute.
15+
An iterator represents a point in a range. Iterator types must provide a comparison operator and increment operator (increment or ++ operators are imported as a member called successor). Iterators can be returned by `begin` and `end` methods to form a range which will automatically be imported as a Sequence in Swift. Iterators can often be inferred by the compiler using the C++ iterator traits, but you can also specify a type is an iterator by using the `import_iterator` swift attribute.
1416

1517
## Trivial Types
1618

1719
Trivial types can be copied by copying the bits of a value of the trivial type and do not need any special destruction logic. Trivial types are inferred by the compiler and cannot be specified using an attribute. Trivial types own their storage, so rules below that apply to owned types also apply to trivial types (specifically regarding projections). Pointers are not trivial types. When Objective-C++ mode is enabled, C++ types that hold Objective-C classes are still considered trivial, even though they technically violate the above contract.
1820

1921
## Unsafe Types
2022

21-
All types which do not fall into one of the above categories are considered unsafe. Any unsafe API, including unsafe types that are copyable and destructible may be imported using the `import_unsafe` swift attribute. There are three kinds of unsafe types: **unsafe pointer types**, **unsafe lifetime types**, and **un-importable types**.
23+
All types which do not fall into one of the above categories are considered unsafe. Any unsafe API, including unsafe types that are copyable and destructible may be imported using the `import_unsafe` swift attribute. There are two kinds of unsafe types: **unsafe pointer types** and **un-importable types**.
2224

2325
**Unsafe Pointer Types:** are types which contain an un-owned pointer. This type is assumed to represent an unsafe memory projection when used as a return type for the method of an owned type.
2426

25-
**Unsafe Lifetime Types:** are types that have custom lifetime operations such as custom copy constructors or custom destructors. These custom lifetime operations are assumed to be unsafe in all contexts.
26-
2727
**Un-importable Types:** are types that are not copyable or destructible. These types cannot be represented in Swift, so they cannot be imported (even if they are marked with the `import_unsafe` attribute).
2828

2929
## API rules
3030

3131
The Swift compiler enforces certain API rules, not to ensure a completely safe C++ API interface, but to prevent especially unsafe patterns that will likely lead to bugs. Many of these unsafe patterns stem from the subtly different lifetime semantics in C++ and Swift and aim to prevent memory projections of owned types. The currently enforced rules are as follows:
3232

33-
* Unsafe lifetime types and un-importable types are not allowed to be used in any contexts.
33+
* Un-importable types are not allowed to be used in any contexts.
3434
* Unsafe pointer types are not allowed to represent unsafe memory projections from owned types. Note: unsafe pointer types *are* allowed to represent memory projections from reference types. Note: the Swift compiler assumes that global and static functions do not return projections.
35-
* Iterators are not allowed to represent unsafe memory projections from owned types. Iterators may be used safely through the CxxIterator and CxxSequence protocols which iterators and ranges automatically conform to.
35+
* Iterators are not allowed to represent unsafe memory projections from owned types. Iterators may be used safely through the `CxxIterator` and `CxxSequence` protocols which iterators and ranges automatically conform to.
3636
* Members of an unsafe type that is explicitly imported using the `import_unsafe` swift attribute are still subject to the above rules. Each individual unsafe member must also have the `import_unsafe` swift attribute to be usable.
3737

include/swift/ClangImporter/ClangImporterRequests.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,6 @@ enum class CxxRecordSemanticsKind {
188188
ExplicitlyUnsafe,
189189
// A record that is either not copyable or not destructible.
190190
MissingLifetimeOperation,
191-
// A record that has custom lifetime operations which we cannot prove are
192-
// safe.
193-
UnsafeLifetimeOperation,
194191
// A record that contains a pointer (aka non-trivial type).
195192
UnsafePointerMember
196193
};

lib/ClangImporter/ClangImporter.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6026,15 +6026,15 @@ CxxRecordSemantics::evaluate(Evaluator &evaluator,
60266026
return CxxRecordSemanticsKind::Iterator;
60276027
}
60286028

6029-
if (!isSufficientlyTrivial(decl)) {
6030-
return CxxRecordSemanticsKind::UnsafeLifetimeOperation;
6031-
}
6032-
60336029
if (hasPointerInSubobjects(decl)) {
60346030
return CxxRecordSemanticsKind::UnsafePointerMember;
60356031
}
60366032

6037-
return CxxRecordSemanticsKind::Trivial;
6033+
if (isSufficientlyTrivial(decl)) {
6034+
return CxxRecordSemanticsKind::Trivial;
6035+
}
6036+
6037+
return CxxRecordSemanticsKind::Owned;
60386038
}
60396039

60406040
bool IsSafeUseOfCxxDecl::evaluate(Evaluator &evaluator,
@@ -6083,8 +6083,7 @@ bool IsSafeUseOfCxxDecl::evaluate(Evaluator &evaluator,
60836083
evaluator, CxxRecordSemantics({recordDecl, desc.ctx}), {});
60846084

60856085
// Always unsafe.
6086-
if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation ||
6087-
semanticsKind == CxxRecordSemanticsKind::UnsafeLifetimeOperation)
6086+
if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation)
60886087
return false;
60896088

60906089
// Always OK.

lib/ClangImporter/ImportDecl.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2494,15 +2494,6 @@ namespace {
24942494
Impl.SwiftContext.AllocateCopy(decl->getNameAsString()),
24952495
"does not have a copy constructor or destructor"));
24962496
return nullptr;
2497-
} else if (semanticsKind ==
2498-
CxxRecordSemanticsKind::UnsafeLifetimeOperation) {
2499-
Impl.addImportDiagnostic(
2500-
decl,
2501-
Diagnostic(diag::record_not_automatically_importable,
2502-
Impl.SwiftContext.AllocateCopy(decl->getNameAsString()),
2503-
"has custom, potentially unsafe copy constructor or "
2504-
"destructor"));
2505-
return nullptr;
25062497
}
25072498

25082499
return VisitRecordDecl(decl);
@@ -2683,8 +2674,7 @@ namespace {
26832674
auto semanticsKind = evaluateOrDefault(
26842675
Impl.SwiftContext.evaluator,
26852676
CxxRecordSemantics({parent, Impl.SwiftContext}), {});
2686-
if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation ||
2687-
semanticsKind == CxxRecordSemanticsKind::UnsafeLifetimeOperation)
2677+
if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation)
26882678
return nullptr;
26892679
}
26902680

test/Interop/Cxx/class/invalid-class-errors.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ struct __attribute__((swift_attr("import_unsafe"))) B {
1919
B(const B&) = delete;
2020
};
2121

22-
struct C {
23-
C(const C&) {}
24-
};
25-
2622
//--- test.swift
2723

2824
import Test
@@ -33,6 +29,4 @@ public func test(x: X) { }
3329
// CHECK: note: record 'A' is not automatically importable: does not have a copy constructor or destructor. Refer to the C++ Interop User Manual to classify this type.
3430
public func test(x: A) { }
3531
// CHECK: note: record 'B' is not automatically importable: does not have a copy constructor or destructor. Refer to the C++ Interop User Manual to classify this type.
36-
public func test(x: B) { }
37-
// CHECK: note: record 'C' is not automatically importable: has custom, potentially unsafe copy constructor or destructor. Refer to the C++ Interop User Manual to classify this type.
38-
public func test(x: C) { }
32+
public func test(x: B) { }

test/Interop/Cxx/stdlib/overlay/std-string-overlay.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-cxx-interop -Xfrontend -validate-tbd-against-ir=none -g)
1+
// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-cxx-interop -Xfrontend -validate-tbd-against-ir=none)
22
//
33
// REQUIRES: executable_test
44
// REQUIRES: OS=macosx || OS=linux-gnu
5-
//
6-
// XFAIL: *
75

86
import StdlibUnittest
97
import std

0 commit comments

Comments
 (0)