Merge pull request #84948 from DougGregor/extern-c-asmname

[SILGen] Map the @_extern(c) C function name over to the asmname of a SIL function
This commit is contained in:
Doug Gregor
2025-10-16 18:27:00 -07:00
committed by GitHub
9 changed files with 57 additions and 21 deletions

View File

@@ -1428,11 +1428,6 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
return NameA->Name.str();
}
if (auto *ExternA = ExternAttr::find(getDecl()->getAttrs(), ExternKind::C)) {
assert(isa<FuncDecl>(getDecl()) && "non-FuncDecl with @_extern should be rejected by typechecker");
return ExternA->getCName(cast<FuncDecl>(getDecl())).str();
}
// Use a given cdecl name for native-to-foreign thunks.
if (getDecl()->getAttrs().hasAttribute<CDeclAttr>())
if (isNativeToForeignThunk()) {

View File

@@ -126,6 +126,12 @@ void SILFunctionBuilder::addFunctionAttributes(
F->setEffectsKind(effectsAttr->getKind());
}
}
if (constant.isFunc() && constant.hasFuncDecl()) {
auto func = constant.getFuncDecl();
if (auto *EA = ExternAttr::find(Attrs, ExternKind::C))
F->setAsmName(EA->getCName(func));
}
}
if (!customEffects.empty()) {

View File

@@ -975,7 +975,7 @@ void Serializer::writeBlockInfoBlock() {
BLOCK_RECORD(sil_block, SIL_SOURCE_LOC_REF);
BLOCK_RECORD(sil_block, SIL_DEBUG_VALUE);
BLOCK_RECORD(sil_block, SIL_DEBUG_VALUE_DELIMITER);
BLOCK_RECORD(sil_block, SIL_EXTRA_STRING);
BLOCK(SIL_INDEX_BLOCK);
BLOCK_RECORD(sil_index_block, SIL_FUNC_NAMES);

View File

@@ -0,0 +1,8 @@
@_extern(c, "takes_a_void_pointer")
public func takes_a_void_pointer(_ pointer: UnsafeRawPointer)
@_alwaysEmitIntoClient
public func callWithNonNull() {
let pointer = UnsafeMutablePointer<Int>.allocate(capacity: 1)
takes_a_void_pointer(UnsafeRawPointer(pointer))
}

View File

@@ -0,0 +1,7 @@
@_extern(c, "takes_a_void_pointer")
public func takes_a_void_pointer(_ pointer: UnsafeRawPointer?)
@_alwaysEmitIntoClient
public func callWithNullable() {
takes_a_void_pointer(nil)
}

View File

@@ -0,0 +1,18 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -enable-experimental-feature Extern -o %t %S/Inputs/extern_with_nullable.swift
// RUN: %target-swift-frontend -emit-module -enable-experimental-feature Extern -o %t %S/Inputs/extern_with_nonnull.swift
// RUN: %target-swift-frontend -emit-sil -o %t -I %t -primary-file %s -module-name main -O
// REQUIRES: swift_feature_Extern
// Don't crash or otherwise fail when inlining multiple functions that reference
// @_extern(c) declarations of the same name but different types at the SIL
// level.
import extern_with_nullable
import extern_with_nonnull
public func main() {
callWithNullable()
callWithNonNull()
}

View File

@@ -2,48 +2,48 @@
// REQUIRES: swift_feature_Extern
// CHECK-DAG: sil hidden_external @my_c_name : $@convention(c) (Int) -> Int
// CHECK-DAG: sil hidden_external [asmname "my_c_name"] @$s8extern_c9withCNameyS2iFTo : $@convention(c) (Int) -> Int
@_extern(c, "my_c_name")
func withCName(_ x: Int) -> Int
// CHECK-DAG: sil hidden_external @take_c_func_ptr : $@convention(c) (@convention(c) (Int) -> Int) -> ()
// CHECK-DAG: sil hidden_external [asmname "take_c_func_ptr"] @$s8extern_c12takeCFuncPtryyS2iXCF : $@convention(c) (@convention(c) (Int) -> Int) -> ()
@_extern(c, "take_c_func_ptr")
func takeCFuncPtr(_ f: @convention(c) (Int) -> Int)
// CHECK-DAG: sil @public_visible : $@convention(c) (Int) -> Int
// CHECK-DAG: sil [asmname "public_visible"] @$s8extern_c16publicVisibilityyS2iF : $@convention(c) (Int) -> Int
@_extern(c, "public_visible")
public func publicVisibility(_ x: Int) -> Int
// CHECK-DAG: sil @private_visible : $@convention(c) (Int) -> Int
// CHECK-DAG: sil [asmname "private_visible"] @$s8extern_c17privateVisibility{{.*}} : $@convention(c) (Int) -> Int
@_extern(c, "private_visible")
private func privateVisibility(_ x: Int) -> Int
// CHECK-DAG: sil hidden_external @withoutCName : $@convention(c) () -> Int
// CHECK-DAG: sil hidden_external [asmname "withoutCName"] @$s8extern_c12withoutCNameSiyF : $@convention(c) () -> Int
@_extern(c)
func withoutCName() -> Int
// CHECK-DAG: sil hidden [ossa] @$s8extern_c10defaultArgyySiFfA_ : $@convention(thin) () -> Int {
// CHECK-DAG: sil hidden_external @default_arg : $@convention(c) (Int) -> ()
// CHECK-DAG: sil hidden_external [asmname "default_arg"] @$s8extern_c10defaultArgyySiF : $@convention(c) (Int) -> ()
@_extern(c, "default_arg")
func defaultArg(_ x: Int = 42)
func main() {
// CHECK-DAG: [[F1:%.+]] = function_ref @my_c_name : $@convention(c) (Int) -> Int
// CHECK-DAG: [[F2:%.+]] = function_ref @take_c_func_ptr : $@convention(c) (@convention(c) (Int) -> Int) -> ()
// CHECK-DAG: [[F1:%.+]] = function_ref @$s8extern_c9withCNameyS2iFTo : $@convention(c) (Int) -> Int
// CHECK-DAG: [[F2:%.+]] = function_ref @$s8extern_c12takeCFuncPtryyS2iXCF : $@convention(c) (@convention(c) (Int) -> Int) -> ()
// CHECK-DAG: apply [[F2]]([[F1]]) : $@convention(c) (@convention(c) (Int) -> Int) -> ()
takeCFuncPtr(withCName)
// CHECK-DAG: [[F3:%.+]] = function_ref @public_visible : $@convention(c) (Int) -> Int
// CHECK-DAG: [[F3:%.+]] = function_ref @$s8extern_c16publicVisibilityyS2iF : $@convention(c) (Int) -> Int
// CHECK-DAG: apply [[F3]]({{.*}}) : $@convention(c) (Int) -> Int
_ = publicVisibility(42)
// CHECK-DAG: [[F4:%.+]] = function_ref @private_visible : $@convention(c) (Int) -> Int
// CHECK-DAG: [[F4:%.+]] = function_ref @$s8extern_c17privateVisibility{{.*}} : $@convention(c) (Int) -> Int
// CHECK-DAG: apply [[F4]]({{.*}}) : $@convention(c) (Int) -> Int
_ = privateVisibility(24)
// CHECK-DAG: [[F5:%.+]] = function_ref @withoutCName : $@convention(c) () -> Int
// CHECK-DAG: [[F5:%.+]] = function_ref @$s8extern_c12withoutCNameSiyF : $@convention(c) () -> Int
// CHECK-DAG: apply [[F5]]() : $@convention(c) () -> Int
_ = withoutCName()
// CHECK-DAG: [[F6:%.+]] = function_ref @$s8extern_c10defaultArgyySiFfA_ : $@convention(thin) () -> Int
// CHECK-DAG: [[DEFAULT_V:%.+]] = apply [[F6]]() : $@convention(thin) () -> Int
// CHECK-DAG: [[F7:%.+]] = function_ref @default_arg : $@convention(c) (Int) -> ()
// CHECK-DAG: [[F7:%.+]] = function_ref @$s8extern_c10defaultArgyySiF : $@convention(c) (Int) -> ()
// CHECK-DAG: apply [[F7]]([[DEFAULT_V]]) : $@convention(c) (Int) -> ()
defaultArg()
}

View File

@@ -9,7 +9,7 @@ func my_extern_func1() // expected-note {{function declared here}}
func my_extern_func2(x: Int)
@_extern(c, "my_other_extern_func")
func my_other_extern_func1() // expected-note {{function declared here}}
func my_other_extern_func1()
@_extern(c, "my_other_extern_func")
func my_other_extern_func2(x: Int)
@@ -18,6 +18,8 @@ public func foo() {
my_extern_func1()
my_extern_func2(x: 42) // expected-error {{function type mismatch, declared as '@convention(thin) () -> ()' but used as '@convention(thin) (Int) -> ()'}}
// @_extern(c, ...) keeps declarations separate at the SIL level, so we do
// not detect a mismatch here.
my_other_extern_func1()
my_other_extern_func2(x: 42) // expected-error {{function type mismatch, declared as '@convention(c) () -> ()' but used as '@convention(c) (Int) -> ()'}}
my_other_extern_func2(x: 42)
}

View File

@@ -4,6 +4,6 @@
// REQUIRES: OS=macosx
@_cdecl("posix_memalign")
func posix_memalign(_ resultPtr:UnsafeMutablePointer<UnsafeMutableRawPointer?>, _ :Int, _ :Int) -> Int32 { // expected-error {{function has wrong linkage to be called from}}
func posix_memalign(_ resultPtr:UnsafeMutablePointer<UnsafeMutableRawPointer?>, _ :Int, _ :Int) -> Int32 { // okay: @_extern(c) declaration is separate
return 0
}