Skip to content

[Swiftify] Don't create safe wrapper for autoreleasing pointers #81568

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

Merged
merged 2 commits into from
May 18, 2025
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
20 changes: 15 additions & 5 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9192,6 +9192,14 @@ static bool SwiftifiableCAT(const clang::CountAttributedType *CAT) {
return CAT && CountedByExpressionValidator().Visit(CAT->getCountExpr());
}

static bool SwiftifiablePointerType(Type swiftType) {
// don't try to transform any Swift types that _SwiftifyImport doesn't know how to handle
Type nonnullType = swiftType->lookThroughSingleOptionalType();
PointerTypeKind PTK;
return nonnullType->isOpaquePointer() ||
(nonnullType->getAnyPointerElementType(PTK) && PTK != PTK_AutoreleasingUnsafeMutablePointer);
}

void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
if (!SwiftContext.LangOpts.hasFeature(Feature::SafeInteropWrappers))
return;
Expand Down Expand Up @@ -9225,10 +9233,11 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
return false;
};
SwiftifyInfoPrinter printer(getClangASTContext(), SwiftContext, out);
Type swiftReturnTy = MappedDecl->getResultInterfaceType();
bool returnIsStdSpan = registerStdSpanTypeMapping(
MappedDecl->getResultInterfaceType(), ClangDecl->getReturnType());
swiftReturnTy, ClangDecl->getReturnType());
auto *CAT = ClangDecl->getReturnType()->getAs<clang::CountAttributedType>();
if (SwiftifiableCAT(CAT)) {
if (SwiftifiableCAT(CAT) && SwiftifiablePointerType(swiftReturnTy)) {
printer.printCountedBy(CAT, SwiftifyInfoPrinter::RETURN_VALUE_INDEX);
attachMacro = true;
}
Expand All @@ -9242,14 +9251,15 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
for (auto [index, clangParam] : llvm::enumerate(ClangDecl->parameters())) {
auto clangParamTy = clangParam->getType();
auto swiftParam = MappedDecl->getParameters()->get(index);
Type swiftParamTy = swiftParam->getInterfaceType();
bool paramHasBoundsInfo = false;
auto *CAT = clangParamTy->getAs<clang::CountAttributedType>();
if (SwiftifiableCAT(CAT)) {
if (SwiftifiableCAT(CAT) && SwiftifiablePointerType(swiftParamTy)) {
printer.printCountedBy(CAT, index);
attachMacro = paramHasBoundsInfo = true;
}
bool paramIsStdSpan = registerStdSpanTypeMapping(
swiftParam->getInterfaceType(), clangParamTy);
swiftParamTy, clangParamTy);
paramHasBoundsInfo |= paramIsStdSpan;

bool paramHasLifetimeInfo = false;
Expand All @@ -9260,7 +9270,7 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
if (clangParam->hasAttr<clang::LifetimeBoundAttr>()) {
printer.printLifetimeboundReturn(
index, !paramHasBoundsInfo &&
swiftParam->getInterfaceType()->isEscapable());
swiftParamTy->isEscapable());
paramHasLifetimeInfo = true;
returnHasLifetimeInfo = true;
}
Expand Down
1 change: 0 additions & 1 deletion test/Interop/C/swiftify-import/Inputs/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,3 @@ module SizedByNoEscapeClang {
header "sized-by-noescape.h"
export *
}

2 changes: 2 additions & 0 deletions test/Interop/ObjC/lit.local.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
if 'objc_interop' not in config.available_features:
config.unsupported = True
4 changes: 4 additions & 0 deletions test/Interop/ObjC/swiftify-import/Inputs/module.modulemap
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module NoSwiftifyClang {
header "objc-no-swiftify.h"
export *
}
9 changes: 9 additions & 0 deletions test/Interop/ObjC/swiftify-import/Inputs/objc-no-swiftify.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#define __counted_by(x) __attribute__((__counted_by__(x)))

@interface SomeClass
- (int)numberOfSegments;
@end

void autoreleaseParam(SomeClass * __autoreleasing * __counted_by(len) p, int len); // expected-note{{declared here}}

SomeClass * __autoreleasing * __counted_by(len) autoreleaseReturn(int len);
2 changes: 0 additions & 2 deletions test/Interop/ObjC/swiftify-import/counted-by-in-class.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
// RUN: %target-swift-ide-test -plugin-path %swift-plugin-dir -I %t/Inputs -enable-experimental-feature SafeInteropWrappers -print-module -module-to-print=Method -source-filename=x | %FileCheck %s
// RUN: %target-swift-frontend -plugin-path %swift-plugin-dir -I %t/Inputs -enable-experimental-feature SafeInteropWrappers %t/method.swift -dump-macro-expansions -typecheck -verify

// REQUIRES: objc_interop

// CHECK: class Foo {
// CHECK: func bar(_ p: UnsafeMutableBufferPointer<Float>)

Expand Down
22 changes: 22 additions & 0 deletions test/Interop/ObjC/swiftify-import/objc-no-swiftify.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// REQUIRES: swift_feature_SafeInteropWrappers

// RUN: %target-swift-ide-test -print-module -module-to-print=NoSwiftifyClang -plugin-path %swift-plugin-dir -I %S/Inputs -source-filename=x -enable-experimental-feature SafeInteropWrappers | %FileCheck %s

// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/NoSwiftify.swiftmodule -I %S/Inputs -enable-experimental-feature SafeInteropWrappers %s -verify -verify-additional-file %S/Inputs/objc-no-swiftify.h

import NoSwiftifyClang

// CHECK-NOT: @_alwaysEmitIntoClient public func callAutoreleaseParam
// CHECK-NOT: @_alwaysEmitIntoClient public func callAutoreleaseReturn

public func callAutoreleaseParam(_ p: UnsafeMutableBufferPointer<SomeClass>) {
// expected-error@+2{{missing argument for parameter #2 in call}}
// expected-error@+1{{cannot convert value of type 'UnsafeMutableBufferPointer<SomeClass>' to expected argument type 'AutoreleasingUnsafeMutablePointer<SomeClass?>'}}
autoreleaseParam(p)
}

public func callAutoreleaseReturn() {
// expected-error@+1{{cannot convert value of type 'AutoreleasingUnsafeMutablePointer<SomeClass?>?' to specified type 'UnsafeMutableBufferPointer<SomeClass>'}}
let p: UnsafeMutableBufferPointer<SomeClass> = autoreleaseReturn(10)
}