From b03795e5f72733b0f4398a10ea888c7602863b20 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Mon, 13 Apr 2015 04:27:02 +0000 Subject: [PATCH] Add a '@convention(xxx)' attribute for specifying function conventions. This is new attribute we're using to coalesce @thin, @objc_block, and @cc, and to extend to new uses like C function pointer types. Parse the new attribute, but preserve support for the old attributes, and print with the old attributes for now to separate out test changes. Migration fixits and test updates to come. I did take the opportunity here to kill off the '@cc(cdecl)' hack for AST-level function pointer types, which are now only spelt with @convention(c). Swift SVN r27247 --- include/swift/AST/Attr.def | 2 +- include/swift/AST/Attr.h | 11 +- include/swift/AST/DiagnosticsParse.def | 8 + include/swift/AST/DiagnosticsSema.def | 8 + lib/AST/ASTPrinter.cpp | 3 +- lib/AST/TypeRepr.cpp | 7 +- lib/Parse/ParseDecl.cpp | 39 ++++- lib/Parse/ParseSIL.cpp | 2 +- lib/SILPasses/Utils/Devirtualize.cpp | 2 +- lib/Sema/TypeCheckType.cpp | 157 +++++++++++++----- .../ctypes_parse_function_pointers.swift | 8 +- test/Parse/c_function_pointers.swift | 24 +-- test/SIL/Parser/basic.sil | 24 +++ test/SILGen/c_function_pointers.swift | 4 +- test/SILGen/objc_blocks_bridging.swift | 6 +- test/attr/attr_convention.swift | 10 ++ 16 files changed, 239 insertions(+), 76 deletions(-) create mode 100644 test/attr/attr_convention.swift diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index 8385a90211c99..2570f89268186 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -31,7 +31,7 @@ #endif // Type attributes -//TYPE_ATTR(convention) +TYPE_ATTR(convention) TYPE_ATTR(noreturn) // SIL-specific attributes diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 34f458f46ad84..ddd6bd1d1d022 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -204,8 +204,8 @@ class TypeAttributes { /// AtLoc - This is the location of the first '@' in the attribute specifier. /// If this is an empty attribute specifier, then this will be an invalid loc. SourceLoc AtLoc; - // TODO: Replace "cc" attribute with proper convention attribute. - Optional cc = None; + Optional deprecatedCC = None; + Optional convention = None; // For an opened existential type, the known ID. Optional OpenedID; @@ -249,8 +249,11 @@ class TypeAttributes { return true; } - bool hasCC() const { return cc.hasValue(); } - StringRef getAbstractCC() const { return *cc; } + bool hasDeprecatedCC() const { return deprecatedCC.hasValue(); } + StringRef getDeprecatedCC() const { return *deprecatedCC; } + + bool hasConvention() const { return convention.hasValue(); } + StringRef getConvention() const { return *convention; } bool hasOwnership() const { return getOwnership() != Ownership::Strong; } Ownership getOwnership() const { diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 2450627ae9c14..42b95c42b6b58 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1034,6 +1034,14 @@ ERROR(cc_attribute_expected_name,attribute_parsing,none, ERROR(cc_attribute_expected_rparen,attribute_parsing,none, "expected ')' after calling convention name for 'cc' attribute", ()) +// convention +ERROR(convention_attribute_expected_lparen,attribute_parsing,none, + "expected '(' after 'convention' attribute", ()) +ERROR(convention_attribute_expected_name,attribute_parsing,none, + "expected convention name identifier in 'convention' attribute", ()) +ERROR(convention_attribute_expected_rparen,attribute_parsing,none, + "expected ')' after convention name for 'convention' attribute", ()) + // objc ERROR(attr_objc_missing_colon,attribute_parsing,none, "missing ':' after selector piece in @objc attribute", ()) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index eecde9564d4ee..42005d14ebb4c 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1771,6 +1771,12 @@ ERROR(objc_block_cannot_be_thin,attribute_parsing,none, "@objc_block function type cannot be @thin", ()) ERROR(attribute_not_supported,attribute_parsing,none, "this attribute is not supported", ()) +ERROR(convention_with_deprecated_representation_attribute,attribute_parsing,none, + "@convention attribute cannot be used with deprecated @%0 attribute", + (StringRef)) +ERROR(unsupported_convention,type_parsing,none, + "convention '%0' not supported", (StringRef)) + // SIL ERROR(sil_local_storage_nested, decl_parsing,none, @@ -1790,6 +1796,8 @@ ERROR(sil_function_multiple_error_results,type_parsing,PointsToFirstBadToken, "SIL function types cannot have multiple @error results", ()) ERROR(unsupported_cc_representation_combo,type_parsing,none, "cc unsupported with this sil representation", ()) +ERROR(unsupported_sil_convention,type_parsing,none, + "convention '%0' not supported in SIL", (StringRef)) // SIL Metatypes ERROR(sil_metatype_without_repr,type_parsing,none, diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 60c0e5da3e9d3..956d352046b6d 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2405,8 +2405,7 @@ class TypePrinter : public TypeVisitor { Printer << "@objc_block "; break; case SILFunctionType::Representation::CFunctionPointer: - //Printer << "@convention(c) "; - Printer << "@cc(cdecl) "; + Printer << "@convention(c) "; break; case SILFunctionType::Representation::Method: //Printer << "@convention(method) "; diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index a1d8ca79c06a8..a8350562ea53b 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -218,8 +218,11 @@ void AttributedTypeRepr::printAttrs(ASTPrinter &Printer) const { if (Attrs.has(TAK_objc_block)) Printer << "@objc_block "; if (Attrs.has(TAK_thin)) Printer << "@thin "; if (Attrs.has(TAK_thick)) Printer << "@thick "; - if (Attrs.cc.hasValue()) { - Printer << "@cc(" << Attrs.cc.getValue() << ")"; + if (Attrs.deprecatedCC.hasValue()) { + Printer << "@cc(" << Attrs.deprecatedCC.getValue() << ")"; + } + if (Attrs.convention.hasValue()) { + Printer << "@convention(" << Attrs.convention.getValue() << ")"; } } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index dcf4b06a1a3e3..5052e3da1cbc2 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1213,7 +1213,7 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) { break; } - // 'cc' attribute. + // Deprecated 'cc' attribute. case TAK_cc: { // Parse the cc name in parens. SourceLoc beginLoc = Tok.getLoc(), nameLoc, endLoc; @@ -1244,7 +1244,42 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) { if (justChecking) return false; if (!name.empty()) - Attributes.cc = name; + Attributes.deprecatedCC = name; + return false; + } + + // Convention attribute. + case TAK_convention: { + // Parse the convention name in parens. + SourceLoc beginLoc = Tok.getLoc(), nameLoc, endLoc; + StringRef name; + if (consumeIfNotAtStartOfLine(tok::l_paren)) { + if (Tok.is(tok::identifier)) { + nameLoc = Tok.getLoc(); + name = Tok.getText(); + consumeToken(); + } else if (!justChecking) { + diagnose(Tok, diag::convention_attribute_expected_name); + } + + // Parse the ')'. We can't use parseMatchingToken if we're in + // just-checking mode. + if (!justChecking) { + parseMatchingToken(tok::r_paren, endLoc, + diag::convention_attribute_expected_rparen, + beginLoc); + } else if (!consumeIf(tok::r_paren)) { + return true; + } + } else if (!justChecking) { + diagnose(Tok, diag::convention_attribute_expected_lparen); + } + + // Don't validate the CC in just-checking mode. + if (justChecking) return false; + + if (!name.empty()) + Attributes.convention = name; return false; } } diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp index 7caa995b02ddc..e742a7fa536d0 100644 --- a/lib/Parse/ParseSIL.cpp +++ b/lib/Parse/ParseSIL.cpp @@ -894,7 +894,7 @@ bool SILParser::parseSILType(SILType &Result, GenericParamList *&GenericParams, // Global functions are implicitly @thin. if (IsFuncDecl && !(attrs.has(TAK_thick) || attrs.has(TAK_thin) || - attrs.has(TAK_objc_block))) { + attrs.has(TAK_objc_block) || attrs.has(TAK_convention))) { // Use a random location. attrs.setAttr(TAK_thin, P.PreviousLoc); } diff --git a/lib/SILPasses/Utils/Devirtualize.cpp b/lib/SILPasses/Utils/Devirtualize.cpp index 904b61495dccd..e3c6574ae651e 100644 --- a/lib/SILPasses/Utils/Devirtualize.cpp +++ b/lib/SILPasses/Utils/Devirtualize.cpp @@ -536,7 +536,7 @@ SILInstruction *swift::tryDevirtualizeApply(ApplyInst *AI) { /// /// \code /// %XX = alloc_ref $Foo - /// %YY = class_method %XX : $Foo, #Foo.get!1 : $@cc(method) @thin ... + /// %YY = class_method %XX : $Foo, #Foo.get!1 : $@convention(method)... /// \endcode /// /// or diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 11e5a334a78b3..477bcb4039bb1 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -28,6 +28,7 @@ #include "swift/Basic/SourceManager.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" using namespace swift; @@ -1277,7 +1278,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, // Pass down the variable function type attributes to the // function-type creator. static const TypeAttrKind FunctionAttrs[] = { - TAK_objc_block, TAK_cc, TAK_thin, TAK_noreturn, + TAK_objc_block, TAK_cc, TAK_convention, TAK_thin, TAK_noreturn, TAK_callee_owned, TAK_callee_guaranteed, TAK_noescape }; @@ -1303,10 +1304,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, for (auto silOnlyAttr : {TAK_thin, TAK_thick}) { checkUnsupportedAttr(silOnlyAttr); } - // TODO: Pick a real syntax for C function pointers. - // For now admit @cc(cdecl) as a syntax for C function pointers. - if (!Context.LangOpts.EnableCFunctionPointers) - checkUnsupportedAttr(TAK_cc); + checkUnsupportedAttr(TAK_cc); } bool hasFunctionAttr = false; @@ -1347,52 +1345,127 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, // TODO: Coalesce the representation attributes into a single 'convention' // attribute. SILFunctionType::Representation rep; - if (thin) - rep = SILFunctionType::Representation::Thin; - else if (block) - rep = SILFunctionType::Representation::Block; - else - rep = SILFunctionType::Representation::Thick; - - if (attrs.hasCC()) { - if (attrs.getAbstractCC() == "cdecl") { - if (rep == SILFunctionType::Representation::Thin) - rep = SILFunctionType::Representation::CFunctionPointer; - else if (rep == SILFunctionType::Representation::Block) - /* OK */; - else - TC.diagnose(attrs.getLoc(TAK_cc), - diag::unsupported_cc_representation_combo); - } else if (attrs.getAbstractCC() == "method" - && rep == SILFunctionType::Representation::Thin) { - rep = SILFunctionType::Representation::Method; - } else if (attrs.getAbstractCC() == "objc_method" - && rep == SILFunctionType::Representation::Thin) { - rep = SILFunctionType::Representation::ObjCMethod; - } else if (attrs.getAbstractCC() == "witness_method" - && rep == SILFunctionType::Representation::Thin) { - rep = SILFunctionType::Representation::WitnessMethod; + + if (attrs.hasConvention()) { + // SIL exposes a greater number of conventions than Swift source. + auto parsedRep = + llvm::StringSwitch> + (attrs.getConvention()) + .Case("thick", SILFunctionType::Representation::Thick) + .Case("block", SILFunctionType::Representation::Block) + .Case("thin", SILFunctionType::Representation::Thin) + .Case("c", SILFunctionType::Representation::CFunctionPointer) + .Case("method", SILFunctionType::Representation::Method) + .Case("objc_method", SILFunctionType::Representation::ObjCMethod) + .Case("witness_method", SILFunctionType::Representation::WitnessMethod) + .Default(None); + if (!parsedRep) { + TC.diagnose(attrs.getLoc(TAK_convention), + diag::unsupported_sil_convention, attrs.getConvention()); + rep = SILFunctionType::Representation::Thin; } else { + rep = *parsedRep; + } + + // Don't allow both @convention and the old representation attrs. + if (attrs.has(TAK_thin)) { + TC.diagnose(attrs.getLoc(TAK_thin), + diag::convention_with_deprecated_representation_attribute, + "thin"); + } + if (attrs.has(TAK_objc_block)) { + TC.diagnose(attrs.getLoc(TAK_objc_block), + diag::convention_with_deprecated_representation_attribute, + "objc_block"); + } + if (attrs.has(TAK_cc)) { TC.diagnose(attrs.getLoc(TAK_cc), - diag::unsupported_cc_representation_combo); + diag::convention_with_deprecated_representation_attribute, + "cc"); + } + } else { + // Handle the old attributes. + // TODO: Warning and fixit to migrate. + if (thin) + rep = SILFunctionType::Representation::Thin; + else if (block) + rep = SILFunctionType::Representation::Block; + else + rep = SILFunctionType::Representation::Thick; + + if (attrs.hasDeprecatedCC()) { + if (attrs.getDeprecatedCC() == "cdecl") { + if (rep == SILFunctionType::Representation::Thin) + rep = SILFunctionType::Representation::CFunctionPointer; + else if (rep == SILFunctionType::Representation::Block) + /* OK */; + else + TC.diagnose(attrs.getLoc(TAK_cc), + diag::unsupported_cc_representation_combo); + } else if (attrs.getDeprecatedCC() == "method" + && rep == SILFunctionType::Representation::Thin) { + rep = SILFunctionType::Representation::Method; + } else if (attrs.getDeprecatedCC() == "objc_method" + && rep == SILFunctionType::Representation::Thin) { + rep = SILFunctionType::Representation::ObjCMethod; + } else if (attrs.getDeprecatedCC() == "witness_method" + && rep == SILFunctionType::Representation::Thin) { + rep = SILFunctionType::Representation::WitnessMethod; + } else { + TC.diagnose(attrs.getLoc(TAK_cc), + diag::unsupported_cc_representation_combo); + } } } // Resolve the function type directly with these attributes. SILFunctionType::ExtInfo extInfo(rep, attrs.has(TAK_noreturn)); - + ty = resolveSILFunctionType(fnRepr, options, extInfo, calleeConvention); } else { + if (attrs.hasDeprecatedCC()) + TC.diagnose(attrs.getLoc(TAK_cc), diag::attribute_not_supported); + FunctionType::Representation rep; - if (thin) - rep = FunctionType::Representation::Thin; - else if (block) - rep = FunctionType::Representation::Block; - else if (attrs.hasCC() && attrs.getAbstractCC() == "cdecl") - rep = FunctionType::Representation::CFunctionPointer; - else - rep = FunctionType::Representation::Swift; + if (attrs.hasConvention()) { + auto parsedRep = + llvm::StringSwitch> + (attrs.getConvention()) + .Case("swift", FunctionType::Representation::Swift) + .Case("block", FunctionType::Representation::Block) + .Case("thin", FunctionType::Representation::Thin) + .Case("c", FunctionType::Representation::CFunctionPointer) + .Default(None); + if (!parsedRep) { + TC.diagnose(attrs.getLoc(TAK_convention), + diag::unsupported_convention, attrs.getConvention()); + rep = FunctionType::Representation::Swift; + } else { + rep = *parsedRep; + } + + // Don't allow both @convention and the old representation attrs. + if (attrs.has(TAK_thin)) { + TC.diagnose(attrs.getLoc(TAK_thin), + diag::convention_with_deprecated_representation_attribute, + "thin"); + } + if (attrs.has(TAK_objc_block)) { + TC.diagnose(attrs.getLoc(TAK_objc_block), + diag::convention_with_deprecated_representation_attribute, + "objc_block"); + } + } else { + // Handle the old attributes. + // TODO: Warning and fixit to migrate. + if (thin) + rep = FunctionType::Representation::Thin; + else if (block) + rep = FunctionType::Representation::Block; + else + rep = FunctionType::Representation::Swift; + } // Resolve the function type directly with these attributes. FunctionType::ExtInfo extInfo(rep, @@ -1406,8 +1479,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, for (auto i : FunctionAttrs) attrs.clearAttribute(i); - attrs.cc = None; - + attrs.deprecatedCC = None; + attrs.convention = None; } else if (hasFunctionAttr) { for (auto i : FunctionAttrs) { if (attrs.has(i)) { diff --git a/test/ClangModules/ctypes_parse_function_pointers.swift b/test/ClangModules/ctypes_parse_function_pointers.swift index 8d27b174f51a2..23d1973058c20 100644 --- a/test/ClangModules/ctypes_parse_function_pointers.swift +++ b/test/ClangModules/ctypes_parse_function_pointers.swift @@ -6,17 +6,17 @@ func testFunctionPointers() { let fp = getFunctionPointer() useFunctionPointer(fp) - let explicitFP: @cc(cdecl) (CInt) -> CInt = fp + let explicitFP: @convention(c) (CInt) -> CInt = fp let wrapper: FunctionPointerWrapper = FunctionPointerWrapper(a: nil, b: nil) let wrapper2 = FunctionPointerWrapper(a: fp, b: fp) useFunctionPointer(wrapper.a) - let _: @cc(cdecl) (CInt) -> CInt = wrapper.b + let _: @convention(c) (CInt) -> CInt = wrapper.b - var anotherFP: @cc(cdecl) (CInt, CLong, UnsafeMutablePointer) -> Void + var anotherFP: @convention(c) (CInt, CLong, UnsafeMutablePointer) -> Void = getFunctionPointer2() useFunctionPointer2(anotherFP) - anotherFP = fp // expected-error {{cannot assign a value of type 'fptr!' to a value of type '@cc(cdecl) (CInt, CLong, UnsafeMutablePointer) -> Void'}} + anotherFP = fp // expected-error {{cannot assign a value of type 'fptr!' to a value of type '@convention(c) (CInt, CLong, UnsafeMutablePointer) -> Void'}} } diff --git a/test/Parse/c_function_pointers.swift b/test/Parse/c_function_pointers.swift index 665097da0677c..665b630ca693b 100644 --- a/test/Parse/c_function_pointers.swift +++ b/test/Parse/c_function_pointers.swift @@ -15,30 +15,30 @@ if true { func local() -> Int { return 0 } func localWithContext() -> Int { return x } - let a: @cc(cdecl) () -> Int = global - let a2: @cc(cdecl) () -> Int = main.global - let b: @cc(cdecl) () -> Int = { 0 } - let c: @cc(cdecl) () -> Int = local + let a: @convention(c) () -> Int = global + let a2: @convention(c) () -> Int = main.global + let b: @convention(c) () -> Int = { 0 } + let c: @convention(c) () -> Int = local // Can't convert a closure with context to a C function pointer - let d: @cc(cdecl) () -> Int = { x } // expected-error{{cannot be formed from a closure that captures context}} - let e: @cc(cdecl) () -> Int = localWithContext // expected-error{{cannot be formed from a local function that captures context}} + let d: @convention(c) () -> Int = { x } // expected-error{{cannot be formed from a closure that captures context}} + let e: @convention(c) () -> Int = localWithContext // expected-error{{cannot be formed from a local function that captures context}} // Can't convert a closure value to a C function pointer let global2 = global - let f: @cc(cdecl) () -> Int = global2 // expected-error{{can only be formed from a reference to a 'func' or a literal closure}} + let f: @convention(c) () -> Int = global2 // expected-error{{can only be formed from a reference to a 'func' or a literal closure}} let globalBlock: @objc_block () -> Int = global - let g: @cc(cdecl) () -> Int = globalBlock // expected-error{{can only be formed from a reference to a 'func' or a literal closure}} + let g: @convention(c) () -> Int = globalBlock // expected-error{{can only be formed from a reference to a 'func' or a literal closure}} // Can convert a function pointer to a block or closure, or assign to another // C function pointer - let h: @cc(cdecl) () -> Int = a + let h: @convention(c) () -> Int = a let i: @objc_block () -> Int = a let j: () -> Int = a // Can't convert a C function pointer from a method. // TODO: Could handle static methods. - let k: @cc(cdecl) () -> Int = S.staticMethod // expected-error{{}} - let m: @cc(cdecl) () -> Int = C.staticMethod // expected-error{{}} - let n: @cc(cdecl) () -> Int = C.classMethod // expected-error{{}} + let k: @convention(c) () -> Int = S.staticMethod // expected-error{{}} + let m: @convention(c) () -> Int = C.staticMethod // expected-error{{}} + let n: @convention(c) () -> Int = C.classMethod // expected-error{{}} } diff --git a/test/SIL/Parser/basic.sil b/test/SIL/Parser/basic.sil index cd4bd3569e3f3..a326fb32cc6ea 100644 --- a/test/SIL/Parser/basic.sil +++ b/test/SIL/Parser/basic.sil @@ -1307,6 +1307,30 @@ bb3: return %4 : $() } +sil @thin_convention : $@convention(thin) () -> () +sil @c_convention : $@convention(c) () -> () +sil @method_convention : $@convention(method) (Int) -> () +sil @objc_method_convention : $@convention(objc_method) (Int) -> () +sil @witness_method_convention : $@convention(witness_method) (Int) -> () + +// CHECK-LABEL: sil @conventions : $@thin (() -> (), @thin () -> (), @cc(cdecl) @thin () -> (), @cc(cdecl) @objc_block () -> (), @cc(method) @thin () -> (), @cc(objc_method) @thin () -> (), @cc(witness_method) @thin () -> ()) -> () { +sil @conventions : $@convention(thin) (@convention(thick) () -> (), + @convention(thin) () -> (), + @convention(c) () -> (), + @convention(block) () -> (), + @convention(method) () -> (), + @convention(objc_method) () -> (), + @convention(witness_method) () -> ()) -> () { +entry(%0 : $@convention(thick) () -> (), + %1 : $@convention(thin) () -> (), + %2 : $@convention(c) () -> (), + %3 : $@convention(block) () -> (), + %4 : $@convention(method) () -> (), + %5 : $@convention(objc_method) () -> (), + %6 : $@convention(witness_method) () -> ()): + return undef : $() +} + // CHECK-LABEL: sil_vtable Foo { // CHECK: #Foo.subscript!getter.1: _TFC3tmp3Foog9subscriptFTVSs5Int32S1__S1_ // CHECK: #Foo.subscript!setter.1: _TFC3tmp3Foos9subscriptFTVSs5Int32S1__S1_ diff --git a/test/SILGen/c_function_pointers.swift b/test/SILGen/c_function_pointers.swift index 233ead23dc5f9..8cdd37f997af5 100644 --- a/test/SILGen/c_function_pointers.swift +++ b/test/SILGen/c_function_pointers.swift @@ -1,13 +1,13 @@ // RUN: %target-swift-frontend -emit-silgen -enable-c-function-pointers %s | FileCheck %s -func values(arg: @cc(cdecl) Int -> Int) -> @cc(cdecl) Int -> Int { +func values(arg: @convention(c) Int -> Int) -> @convention(c) Int -> Int { return arg } // CHECK-LABEL: sil hidden @_TF19c_function_pointers6valuesFcSiSicSiSi // CHECK: bb0(%0 : $@cc(cdecl) @thin (Int) -> Int): // CHECK: return %0 : $@cc(cdecl) @thin (Int) -> Int -func calls(arg: @cc(cdecl) Int -> Int, x: Int) -> Int { +func calls(arg: @convention(c) Int -> Int, x: Int) -> Int { return arg(x) } // CHECK-LABEL: sil hidden @_TF19c_function_pointers5callsFTcSiSiSi_Si diff --git a/test/SILGen/objc_blocks_bridging.swift b/test/SILGen/objc_blocks_bridging.swift index a9e5fe5e32ebb..ee15eda924b69 100644 --- a/test/SILGen/objc_blocks_bridging.swift +++ b/test/SILGen/objc_blocks_bridging.swift @@ -39,7 +39,7 @@ import Foundation // CHECK: bb0([[F:%.*]] : $@cc(cdecl) @thin (Int) -> Int, [[X:%.*]] : $Int, [[SELF:%.*]] : $Foo): // CHECK: [[NATIVE:%.*]] = function_ref @_TFC20objc_blocks_bridging3Foo16cFunctionPointerfS0_FTcSiSi1xSi_Si // CHECK: apply [[NATIVE]]([[F]], [[X]], [[SELF]]) - dynamic func cFunctionPointer(fp: @cc(cdecl) Int -> Int, x: Int) -> Int { + dynamic func cFunctionPointer(fp: @convention(c) Int -> Int, x: Int) -> Int { fp(x) } @@ -62,10 +62,10 @@ import Foundation } // CHECK-LABEL: sil hidden @_TFC20objc_blocks_bridging3Foo19optCFunctionPointerfS0_FTGSqcSSSS_1xSS_GSqSS_ - // CHECK: [[OPT_BUF:%.*]] = alloc_stack $Optional<@cc(cdecl) String -> String> + // CHECK: [[OPT_BUF:%.*]] = alloc_stack $Optional<@convention(c) String -> String> // CHECK: [[FP_BUF:%.*]] = unchecked_take_enum_data_addr [[OPT_BUF]] // CHECK: load [[FP_BUF]] : $*@cc(cdecl) @thin (NSString) -> @autoreleased NSString - dynamic func optCFunctionPointer(fp: (@cc(cdecl) String -> String)?, x: String) -> String? { + dynamic func optCFunctionPointer(fp: (@convention(c) String -> String)?, x: String) -> String? { return fp?(x) } } diff --git a/test/attr/attr_convention.swift b/test/attr/attr_convention.swift new file mode 100644 index 0000000000000..078f27e113672 --- /dev/null +++ b/test/attr/attr_convention.swift @@ -0,0 +1,10 @@ +// RUN: %target-parse-verify-swift + +let f1: Int -> Int = { $0 } +let f2: @convention(swift) Int -> Int = { $0 } +let f3: @convention(block) Int -> Int = { $0 } +let f4: @convention(c) Int -> Int = { $0 } + +let f5: @convention(INTERCAL) Int -> Int = { $0 } // expected-error{{convention 'INTERCAL' not supported}} + +let f6: @convention(block) @objc_block Int -> Int = { $0 } // expected-error{{@convention attribute cannot be used with deprecated @objc_block attribute}}