Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/swift/AST/DiagnosticsClangImporter.def
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ GROUPED_WARNING(clang_ignored_sendable_attr, ClangDeclarationImport, none,
"cannot be added to it",
(Type))

GROUPED_WARNING(warn_clang_ignored_bounds_on_self, ClangDeclarationImport, none,
"bounds attribute '%0' ignored on parameter mapped to 'self'",
(StringRef))
NOTE(note_swift_name_instance_method, none,
"swift_name maps free function to instance method here", ())

WARNING(implicit_bridging_header_imported_from_module,none,
"implicit import of bridging header '%0' via module %1 "
"is deprecated and will be removed in a later version of Swift",
Expand Down
64 changes: 54 additions & 10 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9403,6 +9403,22 @@ void ClangImporter::Implementation::addOptionSetTypealiases(
selfType);
}

// until CountAttributedType::getAttributeName lands in our LLVM branch
static StringRef getAttributeName(const clang::CountAttributedType *CAT) {
switch (CAT->getKind()) {
case clang::CountAttributedType::CountedBy:
return "__counted_by";
case clang::CountAttributedType::CountedByOrNull:
return "__counted_by_or_null";
case clang::CountAttributedType::SizedBy:
return "__sized_by";
case clang::CountAttributedType::SizedByOrNull:
return "__sized_by_or_null";
case clang::CountAttributedType::EndedBy:
llvm_unreachable("CountAttributedType cannot be ended_by");
}
}

void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) {
if (!SwiftContext.LangOpts.hasFeature(Feature::SafeInteropWrappers))
return;
Expand All @@ -9419,9 +9435,6 @@ void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) {
ClangDecl->getAccess() == clang::AS_private)
return;

if (ClangDecl->getNumParams() != MappedDecl->getParameters()->size())
return;

MacroDecl *SwiftifyImportDecl = dyn_cast_or_null<MacroDecl>(getKnownSingleDecl(SwiftContext, "_SwiftifyImport"));
if (!SwiftifyImportDecl)
return;
Expand Down Expand Up @@ -9478,14 +9491,44 @@ void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) {
true);
returnHasLifetimeInfo = true;
}

bool isClangInstanceMethod =
isa<clang::CXXMethodDecl>(ClangDecl) &&
!isa<clang::CXXConstructorDecl>(ClangDecl) &&
cast<clang::CXXMethodDecl>(ClangDecl)->isInstance();
size_t swiftNumParams = MappedDecl->getParameters()->size() -
(ClangDecl->isVariadic() ? 1 : 0);
ASSERT((MappedDecl->isImportAsInstanceMember() == isClangInstanceMethod) ==
(ClangDecl->getNumParams() == swiftNumParams));

size_t selfParamIndex = MappedDecl->isImportAsInstanceMember()
? MappedDecl->getSelfIndex()
: ClangDecl->getNumParams();
for (auto [index, clangParam] : llvm::enumerate(ClangDecl->parameters())) {
auto clangParamTy = clangParam->getType();
auto swiftParam = MappedDecl->getParameters()->get(index);
int mappedIndex = index < selfParamIndex ? index :
index > selfParamIndex ? index - 1 :
SwiftifyInfoPrinter::SELF_PARAM_INDEX;
ParamDecl *swiftParam = nullptr;
if (mappedIndex == SwiftifyInfoPrinter::SELF_PARAM_INDEX) {
swiftParam = MappedDecl->getImplicitSelfDecl(/*createIfNeeded*/true);
} else {
swiftParam = MappedDecl->getParameters()->get(mappedIndex);
}
ASSERT(swiftParam);
Type swiftParamTy = swiftParam->getInterfaceType();
bool paramHasBoundsInfo = false;
auto *CAT = clangParamTy->getAs<clang::CountAttributedType>();
if (SwiftifiableCAT(getClangASTContext(), CAT, swiftParamTy)) {
printer.printCountedBy(CAT, index);
if (CAT && mappedIndex == SwiftifyInfoPrinter::SELF_PARAM_INDEX) {
diagnose(HeaderLoc(clangParam->getLocation()),
diag::warn_clang_ignored_bounds_on_self, getAttributeName(CAT));
auto swiftName = ClangDecl->getAttr<clang::SwiftNameAttr>();
ASSERT(swiftName &&
"free function mapped to instance method without swift_name??");
diagnose(HeaderLoc(swiftName->getLocation()),
diag::note_swift_name_instance_method);
} else if (SwiftifiableCAT(getClangASTContext(), CAT, swiftParamTy)) {
printer.printCountedBy(CAT, mappedIndex);
attachMacro = paramHasBoundsInfo = true;
}
bool paramIsStdSpan = registerStdSpanTypeMapping(
Expand All @@ -9494,14 +9537,16 @@ void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) {

bool paramHasLifetimeInfo = false;
if (clangParam->hasAttr<clang::NoEscapeAttr>()) {
printer.printNonEscaping(index);
printer.printNonEscaping(mappedIndex);
paramHasLifetimeInfo = true;
}
if (clangParam->hasAttr<clang::LifetimeBoundAttr>()) {
// If this parameter has bounds info we will tranform it into a Span,
// so then it will no longer be Escapable.
bool willBeEscapable = swiftParamTy->isEscapable() && !paramHasBoundsInfo;
printer.printLifetimeboundReturn(index, willBeEscapable);
bool willBeEscapable = swiftParamTy->isEscapable() &&
(!paramHasBoundsInfo ||
mappedIndex == SwiftifyInfoPrinter::SELF_PARAM_INDEX);
printer.printLifetimeboundReturn(mappedIndex, willBeEscapable);
paramHasLifetimeInfo = true;
returnHasLifetimeInfo = true;
}
Expand All @@ -9512,7 +9557,6 @@ void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) {
attachMacro = true;
printer.printAvailability();
printer.printTypeMapping(typeMapping);

}

if (attachMacro) {
Expand Down
9 changes: 8 additions & 1 deletion lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,14 @@ struct FunctionCallBuilder: BoundsCheckedThunkBuilder {
let functionRef = DeclReferenceExprSyntax(baseName: base.name)
let args: [ExprSyntax] = base.signature.parameterClause.parameters.enumerated()
.map { (i: Int, param: FunctionParameterSyntax) in
return pointerArgs[i] ?? ExprSyntax("\(param.name)")
if let overrideArg = pointerArgs[i] {
return overrideArg
}
if isInout(getParam(base.signature, i).type) {
return ExprSyntax("&\(param.name)")
} else {
return ExprSyntax("\(param.name)")
}
}
let labels: [TokenSyntax?] = base.signature.parameterClause.parameters.map { param in
let firstName = param.firstName.trimmed
Expand Down
1 change: 1 addition & 0 deletions stdlib/public/Cxx/libstdcxx/libstdcxx.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ module std {
header "ostream"
header "queue"
header "set"
header "span"
header "sstream"
header "stack"
header "stdexcept"
Expand Down
195 changes: 195 additions & 0 deletions test/Interop/C/swiftify-import/import-as-instance-method.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
// REQUIRES: swift_feature_SafeInteropWrappers

// RUN: %empty-directory(%t)
// RUN: split-file %s %t

// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/Test.swiftmodule -I %t%{fs-sep}Inputs -enable-experimental-feature SafeInteropWrappers -strict-memory-safety -verify -verify-additional-file %t%{fs-sep}Inputs%{fs-sep}instance.h %t/test.swift -I %bridging-path -DVERIFY
// RUN: env SWIFT_BACKTRACE="" %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/Test.swiftmodule -I %t/Inputs -enable-experimental-feature SafeInteropWrappers -strict-memory-safety -warnings-as-errors -Xcc -Werror %t/test.swift -dump-macro-expansions -I %bridging-path 2> %t/out.txt
// RUN: diff --strip-trailing-cr %t/out.txt %t/out.expected

//--- test.swift
import Instance

@available(macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4, *)
func foo(_ p: inout MutableSpan<CInt>, a: A, aa: inout A, c: C/*, b: B, bb: inout B*/) {
aa.basic(&p)
aa.bar(&p)
a.constSelf(&p)
a.valSelf(&p)
let _: MutableSpan<CInt> = a.lifetimeBoundSelf(3)
c.refSelf(&p)
//b.nonescaping(&p)
//let _: MutableSpan<CInt> = bb.nonescapingLifetimebound(73)

#if VERIFY
aa.countedSelf(&p)
a.basic(&p) // expected-error{{cannot use mutating member on immutable value: 'a' is a 'let' constant}}
#endif
}

//--- Inputs/instance.h
#include <ptrcheck.h>
#include <lifetimebound.h>
#include <swift/bridging>

struct A {};
struct SWIFT_NONESCAPABLE B {};
struct SWIFT_IMMORTAL_REFERENCE C {};

void basic(struct A *a, int * __counted_by(len) p __noescape, int len) __attribute__((swift_name("A.basic(self:_:_:)")));

void renamed(struct A *a, int * __counted_by(len) p __noescape, int len) __attribute__((swift_name("A.bar(self:_:_:)")));

void countedSelf(struct A * __counted_by(len)
a, // expected-warning{{bounds attribute '__counted_by' ignored on parameter mapped to 'self'}}
int * __counted_by(len) p __noescape, int len)
__attribute__((
swift_name // expected-note{{swift_name maps free function to instance method here}}
("A.countedSelf(self:_:_:)")));

void constSelf(const struct A *a, int * __counted_by(len) p __noescape, int len) __attribute__((swift_name("A.constSelf(self:_:_:)")));

void valSelf(struct A a, int * __counted_by(len) p __noescape, int len) __attribute__((swift_name("A.valSelf(self:_:_:)")));

void refSelf(struct C *c, int * __counted_by(len) p __noescape, int len) __attribute__((swift_name("C.refSelf(self:_:_:)")));

int * __counted_by(len) lifetimeBoundSelf(struct A a __lifetimebound, int len) __attribute__((swift_name("A.lifetimeBoundSelf(self:_:)")));

//void nonescaping(const struct B *d, int * __counted_by(len) p __noescape, int len) __attribute__((swift_name("B.nonescaping(self:_:_:)")));

// Swift 6.2 error: a mutating method cannot have a ~Escapable 'self'
// requires https://github.com/swiftlang/swift/pull/84010
//int * __counted_by(len) nonescapingLifetimebound(struct B *d __lifetimebound, int len) __attribute__((swift_name("B.nonescapingLifetimebound(self:_:)")));

//--- Inputs/module.modulemap
module Instance {
header "instance.h"
}

//--- out.expected
@__swiftmacro_So1AV5basic15_SwiftifyImportfMp_.swift
------------------------------
/// This is an auto-generated wrapper for safer interop
@_alwaysEmitIntoClient @available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) @_lifetime(p: copy p) @_disfavoredOverload
public mutating func basic(_ p: inout MutableSpan<Int32>) {
let len = Int32(exactly: p.count)!
return unsafe p.withUnsafeMutableBufferPointer { _pPtr in
return unsafe basic(_pPtr.baseAddress!, len)
}
}
------------------------------
@__swiftmacro_So5basic15_SwiftifyImportfMp_.swift
------------------------------
/// This is an auto-generated wrapper for safer interop
@available(swift, obsoleted: 3, renamed: "A.basic(self:_:_:)") @_alwaysEmitIntoClient @available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) @_lifetime(p: copy p) @_disfavoredOverload
public func basic(_ a: UnsafeMutablePointer<A>!, _ p: inout MutableSpan<Int32>) {
let len = Int32(exactly: p.count)!
return unsafe p.withUnsafeMutableBufferPointer { _pPtr in
return unsafe basic(a, _pPtr.baseAddress!, len)
}
}
------------------------------
@__swiftmacro_So1AV3bar15_SwiftifyImportfMp_.swift
------------------------------
/// This is an auto-generated wrapper for safer interop
@_alwaysEmitIntoClient @available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) @_lifetime(p: copy p) @_disfavoredOverload
public mutating func bar(_ p: inout MutableSpan<Int32>) {
let len = Int32(exactly: p.count)!
return unsafe p.withUnsafeMutableBufferPointer { _pPtr in
return unsafe bar(_pPtr.baseAddress!, len)
}
}
------------------------------
@__swiftmacro_So7renamed15_SwiftifyImportfMp_.swift
------------------------------
/// This is an auto-generated wrapper for safer interop
@available(swift, obsoleted: 3, renamed: "A.bar(self:_:_:)") @_alwaysEmitIntoClient @available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) @_lifetime(p: copy p) @_disfavoredOverload
public func renamed(_ a: UnsafeMutablePointer<A>!, _ p: inout MutableSpan<Int32>) {
let len = Int32(exactly: p.count)!
return unsafe p.withUnsafeMutableBufferPointer { _pPtr in
return unsafe renamed(a, _pPtr.baseAddress!, len)
}
}
------------------------------
@__swiftmacro_So1AV9constSelf15_SwiftifyImportfMp_.swift
------------------------------
/// This is an auto-generated wrapper for safer interop
@_alwaysEmitIntoClient @available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) @_lifetime(p: copy p) @_disfavoredOverload
public func constSelf(_ p: inout MutableSpan<Int32>) {
let len = Int32(exactly: p.count)!
return unsafe p.withUnsafeMutableBufferPointer { _pPtr in
return unsafe constSelf(_pPtr.baseAddress!, len)
}
}
------------------------------
@__swiftmacro_So9constSelf15_SwiftifyImportfMp_.swift
------------------------------
/// This is an auto-generated wrapper for safer interop
@available(swift, obsoleted: 3, renamed: "A.constSelf(self:_:_:)") @_alwaysEmitIntoClient @available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) @_lifetime(p: copy p) @_disfavoredOverload
public func constSelf(_ a: UnsafePointer<A>!, _ p: inout MutableSpan<Int32>) {
let len = Int32(exactly: p.count)!
return unsafe p.withUnsafeMutableBufferPointer { _pPtr in
return unsafe constSelf(a, _pPtr.baseAddress!, len)
}
}
------------------------------
@__swiftmacro_So1AV7valSelf15_SwiftifyImportfMp_.swift
------------------------------
/// This is an auto-generated wrapper for safer interop
@_alwaysEmitIntoClient @available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) @_lifetime(p: copy p) @_disfavoredOverload
public func valSelf(_ p: inout MutableSpan<Int32>) {
let len = Int32(exactly: p.count)!
return unsafe p.withUnsafeMutableBufferPointer { _pPtr in
return unsafe valSelf(_pPtr.baseAddress!, len)
}
}
------------------------------
@__swiftmacro_So7valSelf15_SwiftifyImportfMp_.swift
------------------------------
/// This is an auto-generated wrapper for safer interop
@available(swift, obsoleted: 3, renamed: "A.valSelf(self:_:_:)") @_alwaysEmitIntoClient @available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) @_lifetime(p: copy p) @_disfavoredOverload
public func valSelf(_ a: A, _ p: inout MutableSpan<Int32>) {
let len = Int32(exactly: p.count)!
return unsafe p.withUnsafeMutableBufferPointer { _pPtr in
return unsafe valSelf(a, _pPtr.baseAddress!, len)
}
}
------------------------------
@__swiftmacro_So1AV17lifetimeBoundSelf15_SwiftifyImportfMp_.swift
------------------------------
/// This is an auto-generated wrapper for safer interop
@_alwaysEmitIntoClient @available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) @_lifetime(borrow self) @_disfavoredOverload
public func lifetimeBoundSelf(_ len: Int32) -> MutableSpan<Int32> {
return unsafe _swiftifyOverrideLifetime(MutableSpan<Int32>(_unsafeStart: unsafe lifetimeBoundSelf(len), count: Int(len)), copying: ())
}
------------------------------
@__swiftmacro_So17lifetimeBoundSelf15_SwiftifyImportfMp_.swift
------------------------------
/// This is an auto-generated wrapper for safer interop
@available(swift, obsoleted: 3, renamed: "A.lifetimeBoundSelf(self:_:)") @_alwaysEmitIntoClient @available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) @_lifetime(borrow a) @_disfavoredOverload
public func lifetimeBoundSelf(_ a: A, _ len: Int32) -> MutableSpan<Int32> {
return unsafe _swiftifyOverrideLifetime(MutableSpan<Int32>(_unsafeStart: unsafe lifetimeBoundSelf(a, len), count: Int(len)), copying: ())
}
------------------------------
@__swiftmacro_So1CV7refSelf15_SwiftifyImportfMp_.swift
------------------------------
/// This is an auto-generated wrapper for safer interop
@_alwaysEmitIntoClient @available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) @_lifetime(p: copy p) @_disfavoredOverload
public func refSelf(_ p: inout MutableSpan<Int32>) {
let len = Int32(exactly: p.count)!
return unsafe p.withUnsafeMutableBufferPointer { _pPtr in
return unsafe refSelf(_pPtr.baseAddress!, len)
}
}
------------------------------
@__swiftmacro_So7refSelf15_SwiftifyImportfMp_.swift
------------------------------
/// This is an auto-generated wrapper for safer interop
@available(swift, obsoleted: 3, renamed: "C.refSelf(self:_:_:)") @_alwaysEmitIntoClient @available(visionOS 1.0, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *) @_lifetime(p: copy p) @_disfavoredOverload
public func refSelf(_ c: C!, _ p: inout MutableSpan<Int32>) {
let len = Int32(exactly: p.count)!
return unsafe p.withUnsafeMutableBufferPointer { _pPtr in
return unsafe refSelf(c, _pPtr.baseAddress!, len)
}
}
------------------------------
3 changes: 0 additions & 3 deletions test/Interop/Cxx/class/access/swiftify-private-fileid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@

// REQUIRES: swift_feature_SafeInteropWrappers

// FIXME swift-ci linux tests do not support std::span
// UNSUPPORTED: OS=linux-gnu, OS=linux-android, OS=linux-androideabi

//--- Inputs/swiftify-non-public.h
#pragma once

Expand Down
3 changes: 0 additions & 3 deletions test/Interop/Cxx/stdlib/std-span-interface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
// REQUIRES: swift_feature_SafeInteropWrappers
// REQUIRES: swift_feature_Lifetimes

// FIXME swift-ci linux tests do not support std::span
// UNSUPPORTED: OS=linux-gnu, OS=linux-android, OS=linux-androideabi

#if !BRIDGING_HEADER
import StdSpan
#endif
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
// RUN: %target-run-simple-swift(-plugin-path %swift-plugin-dir -I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -swift-version 6 -Xfrontend -disable-availability-checking -Xcc -std=c++20 -enable-experimental-feature LifetimeDependence -enable-experimental-feature SafeInteropWrappers)

// FIXME swift-ci linux tests do not support std::span
// UNSUPPORTED: OS=linux-gnu

// TODO: test failed in Windows PR testing: rdar://144384453
// UNSUPPORTED: OS=windows-msvc

Expand Down
3 changes: 0 additions & 3 deletions test/Interop/Cxx/stdlib/use-std-span-typechecker.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
// RUN: %target-typecheck-verify-swift -I %S/Inputs -enable-experimental-cxx-interop -Xcc -std=c++20 2>&1

// FIXME swift-ci linux tests do not support std::span
// UNSUPPORTED: OS=linux-gnu

import StdSpan

let arr: [Int32] = [1, 2, 3]
Expand Down
3 changes: 0 additions & 3 deletions test/Interop/Cxx/stdlib/use-std-span.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -std=c++20)
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -std=c++20 -Xcc -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG)

// FIXME swift-ci linux tests do not support std::span
// UNSUPPORTED: OS=linux-gnu

// TODO: test failed in Windows PR testing: rdar://144384453
// UNSUPPORTED: OS=windows-msvc

Expand Down
Loading