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
3 changes: 3 additions & 0 deletions lib/SIL/IR/SILDeclRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ bool swift::requiresForeignEntryPoint(ValueDecl *vd) {
if (vd->hasClangNode())
return true;

if (ExternAttr::find(vd->getAttrs(), ExternKind::C))
return true;

if (auto *accessor = dyn_cast<AccessorDecl>(vd)) {
// Property accessors should be generated alongside the property.
if (accessor->isGetterOrSetter()) {
Expand Down
2 changes: 0 additions & 2 deletions lib/SIL/IR/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4474,8 +4474,6 @@ TypeConverter::getDeclRefRepresentation(SILDeclRef c) {
case SILDeclRef::Kind::Func:
if (c.getDecl()->getDeclContext()->isTypeContext())
return SILFunctionTypeRepresentation::Method;
if (ExternAttr::find(c.getDecl()->getAttrs(), ExternKind::C))
return SILFunctionTypeRepresentation::CFunctionPointer;
return SILFunctionTypeRepresentation::Thin;

case SILDeclRef::Kind::Destroyer:
Expand Down
3 changes: 3 additions & 0 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,9 @@ emitRValueForDecl(SILLocation loc, ConcreteDeclRef declRef, Type ncRefType,
// If the referenced decl isn't a VarDecl, it should be a constant of some
// sort.
SILDeclRef silDeclRef(decl);
if (ExternAttr::find(decl->getAttrs(), ExternKind::C))
silDeclRef = silDeclRef.asForeign();

assert(silDeclRef.getParameterListCount() == 1);
auto substType = cast<AnyFunctionType>(refType);
auto typeContext = getFunctionTypeInfo(substType);
Expand Down
5 changes: 5 additions & 0 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2565,6 +2565,11 @@ InterfaceTypeRequest::evaluate(Evaluator &eval, ValueDecl *D) const {
infoBuilder = infoBuilder.withSendingResult();
}

if (ExternAttr::find(D->getAttrs(), ExternKind::C)) {
infoBuilder = infoBuilder.withRepresentation(
FunctionTypeRepresentation::CFunctionPointer);
}

// Lifetime dependencies only apply to the outer function type.
if (!hasSelf && lifetimeDependenceInfo.has_value()) {
infoBuilder =
Expand Down
28 changes: 20 additions & 8 deletions test/SILGen/extern_c.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,58 @@
@_extern(c, "my_c_name")
func withCName(_ x: Int) -> Int

// CHECK-DAG: sil hidden_external [asmname "take_c_func_ptr"] @$s8extern_c12takeCFuncPtryyS2iXCF : $@convention(c) (@convention(c) (Int) -> Int) -> ()
// CHECK-DAG: sil hidden_external [asmname "take_c_func_ptr"] @$s8extern_c12takeCFuncPtryyS2iXCFTo : $@convention(c) (@convention(c) (Int) -> Int) -> ()
@_extern(c, "take_c_func_ptr")
func takeCFuncPtr(_ f: @convention(c) (Int) -> Int)

// CHECK-DAG: sil [asmname "public_visible"] @$s8extern_c16publicVisibilityyS2iF : $@convention(c) (Int) -> Int
// CHECK-DAG: sil [serialized] [asmname "public_visible"] @$s8extern_c16publicVisibilityyS2iFTo : $@convention(c) (Int) -> Int
@_extern(c, "public_visible")
public func publicVisibility(_ x: 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 [asmname "withoutCName"] @$s8extern_c12withoutCNameSiyF : $@convention(c) () -> Int
// CHECK-DAG: sil hidden_external [asmname "withoutCName"] @$s8extern_c12withoutCNameSiyFTo : $@convention(c) () -> Int
@_extern(c)
func withoutCName() -> Int

// CHECK-DAG: sil hidden [ossa] @$s8extern_c10defaultArgyySiFfA_ : $@convention(thin) () -> Int {
// CHECK-DAG: sil hidden_external [asmname "default_arg"] @$s8extern_c10defaultArgyySiF : $@convention(c) (Int) -> ()
// CHECK-DAG: sil hidden_external [asmname "default_arg"] @$s8extern_c10defaultArgyySiFTo : $@convention(c) (Int) -> ()
@_extern(c, "default_arg")
func defaultArg(_ x: Int = 42)

func callMe(body: (Int) -> Int) -> Int {
return body(17)
}

func main() {
// 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: [[F2:%.+]] = function_ref @$s8extern_c12takeCFuncPtryyS2iXCFTo : $@convention(c) (@convention(c) (Int) -> Int) -> ()
// CHECK-DAG: apply [[F2]]([[F1]]) : $@convention(c) (@convention(c) (Int) -> Int) -> ()
takeCFuncPtr(withCName)
// CHECK-DAG: [[F3:%.+]] = function_ref @$s8extern_c16publicVisibilityyS2iF : $@convention(c) (Int) -> Int
// CHECK-DAG: [[F3:%.+]] = function_ref @$s8extern_c16publicVisibilityyS2iFTo : $@convention(c) (Int) -> Int
// CHECK-DAG: apply [[F3]]({{.*}}) : $@convention(c) (Int) -> Int
_ = publicVisibility(42)
// 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 @$s8extern_c12withoutCNameSiyF : $@convention(c) () -> Int
// CHECK-DAG: [[F5:%.+]] = function_ref @$s8extern_c12withoutCNameSiyFTo : $@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 @$s8extern_c10defaultArgyySiF : $@convention(c) (Int) -> ()
// CHECK-DAG: [[F7:%.+]] = function_ref @$s8extern_c10defaultArgyySiFTo : $@convention(c) (Int) -> ()
// CHECK-DAG: apply [[F7]]([[DEFAULT_V]]) : $@convention(c) (Int) -> ()
defaultArg()

// CHECK-DAG: [[CREF:%[0-9]+]] = function_ref @$s8extern_c16publicVisibilityyS2iFTo : $@convention(c) (Int) -> Int
// CHECK-DAG: [[THUNK:%[0-9]+]] = function_ref @$sS2iIetCyd_S2iIegyd_TR : $@convention(thin) (Int, @convention(c) (Int) -> Int) -> Int
// CHECK-DAG: [[APPLIED:%[0-9]+]] = partial_apply [callee_guaranteed] [[THUNK]]([[CREF]]) : $@convention(thin) (Int, @convention(c) (Int) -> Int) -> Int
// CHECK-DAG: [[NOESCAPE_APPLIED:%[0-9]+]] = convert_escape_to_noescape [not_guaranteed] [[APPLIED]] to $@noescape @callee_guaranteed (Int) -> Int
// CHECK-DAG: [[CALL_ME:%[0-9]+]] = function_ref @$s8extern_c6callMe4bodyS3iXE_tF
// CHECK-DAG: apply [[CALL_ME]]([[NOESCAPE_APPLIED]]) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed (Int) -> Int) -> Int
_ = callMe(body: publicVisibility)
}

main()