-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[cxx-interop] Flip the switch: only import safe APIs. #59624
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
lib/ClangImporter/ImportDecl.cpp
Outdated
|
||
// Recursively checks that there are no pointers, user-provided copy | ||
// constructors, or destructors in any fields or base classes. | ||
static bool isSufficientlyTrivial(const clang::CXXRecordDecl *decl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may want to cache this.
lib/ClangImporter/ImportDecl.cpp
Outdated
if (bridgingInfo.getClangName() != "begin" && | ||
bridgingInfo.getClangName() != "end" && | ||
!decl->isOverloadedOperator() && !decl->isStatic() && | ||
!hasUnsafeAPIAttr(decl) && !hasImportAsRefAttr(decl->getParent())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- add tests for all of these
inline const char *inNonTrivial() const { return "NonTrivial::inNonTrivial"; } | ||
inline const char *inNonTrivialWithArgs(int a, int b) const { | ||
inline const char *inNonTrivial() const | ||
__attribute__((swift_attr("import_unsafe_api"))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review note: I was originally going to update all of these tests to be safe APIs, but I decided that should happen in a follow up PR. These are testing very specific things, so we should upgrade them slowly/incrementally to ensure we don't lose test coverage and regress.
This essentially makes the This makes me think that ClangImporter might not be the right place for this logic. I think a better approach would be to import all APIs in ClangImporter, and then reject unsafe calls during type checking. Let's discuss offline :) |
bc301b4
to
44cb846
Compare
44cb846
to
0198e0f
Compare
@@ -1,37 +0,0 @@ | |||
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not something that we want people to be able to do anymore. The correct way to do this is with the stdlib overlay, which we already have tests for.
ea20131
to
494ff2d
Compare
@swift-ci please test |
abd1fd9
to
f32c529
Compare
@swift-ci please test |
@@ -0,0 +1,37 @@ | |||
# C++ Interop User Manual |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is user manual lacks introduction and basic context to be able to understand the sections below. Is it meant to be a manual for forward interop, or bidirectional whole interop? How is the user supposed to read it and understand what categories are without some sort of basic introduction.
return CxxRecordSemanticsKind::Owned; | ||
} | ||
|
||
if (hasIteratorAPIAttr(decl)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should require the user to annotate all iterators with an attribute. Swift can detect that the type is an iterator statically without an attribute by doing clangRecordDecl->lookup(getClangASTContext().Idents.get("iterator_category"))
– if there is a subtype called iterator_category
, then this type is an iterator (see swift::conformToCxxIteratorIfNeeded
from #60001).
If the iterator type doesn't define iterator_category
, then the user can add an attribute, but I don't think we should require attributes for something we can correctly deduce statically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed offline: we will use both to determine what's an iterator.
stdlib/public/Cxx/std/String.swift
Outdated
let count = string.count | ||
self.init(count, value_type(0)) | ||
var string = string | ||
string.withUTF8 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for fixing this! 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought this would be a small perf improvement but actually seems to not work. We can investigate in a separate follow up patch.
!copyAssignOperatorIsDefaulted(decl)) || | ||
(decl->hasUserDeclaredDestructor() && | ||
!decl->getDestructor()->isDefaulted())) | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand why a type with a custom copy constructor is unsafe. I think this is probably too restrictive, let's discuss.
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: | ||
|
||
* Unsafe lifetime types and un-importable types are not allowed to be used in any contexts. | ||
* 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should you clarify that unsafe pointers are allowed to represent memory projections from immortal reference types here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have the idea of immortal vs other foreign reference types. Above it clarifies that foreign reference types must be immortal or manually managed, so I think it's fine. This states our current support, not our future plans.
|
||
import Test | ||
|
||
// CHECK: note: record 'X' is not defined (incomplete) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NuriAmari thanks again for building all the infrastructure for these diagnostics. It made it super easy (one line) to add diagnostics for all these other cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My pleasure, glad it's being put to good use 👍
@swift-ci please test. |
1 similar comment
@swift-ci please test. |
This makes "owned" the default kind for records that have custom copy constructors and no pointer-members.
…nter types. Previously types containing pointers would mark all C++ methods as unsafe.
781850c
to
228a886
Compare
@swift-ci please test. |
228a886
to
12933bf
Compare
@swift-ci please test. |
@swift-ci please test. |
@swift-ci please test. |
For some reason this isn't working, so I reverted to the previous approach. We can try to re-visit this in the future for a potential perf improvement.
@swift-ci please test. |
@swift-ci please smoke test linux. |
1 similar comment
@swift-ci please smoke test linux. |
07a97f8
to
e62ce9b
Compare
@swift-ci please smoke test linux. |
e62ce9b
to
20ffe0b
Compare
@swift-ci please smoke test linux. |
20ffe0b
to
ba7e6e4
Compare
@swift-ci please smoke test. |
@swift-ci please test. |
This patch adds is the first of many to flip the switch and stop eagerly importing C++ APIs. We will now only import safe APIs or APIs that are annotated by the user. I will follow this patch up with improved diagnostics, testing, and documentation.