Skip to content

Parser: Reject the old string syntax for @cdecl and allow the experimental feature in production #82789

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ EXPERIMENTAL_FEATURE(ClosureBodyMacro, true)
EXPERIMENTAL_FEATURE(AllowRuntimeSymbolDeclarations, true)

/// Allow use of `@cdecl`
EXPERIMENTAL_FEATURE(CDecl, false)
EXPERIMENTAL_FEATURE(CDecl, true)

/// Allow use of `@extensible` on public enums
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(ExtensibleAttribute, false)
Expand Down
12 changes: 2 additions & 10 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3009,14 +3009,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
}

case DeclAttrKind::CDecl: {
if (!AttrName.starts_with("_") &&

// Backwards support for @cdecl("stringId"). Remove before enabling in
// production so we accept only the identifier format.
lookahead<bool>(1, [&](CancellableBacktrackingScope &) {
return Tok.isNot(tok::string_literal);
})) {

if (!AttrName.starts_with("_")) {
std::optional<StringRef> CName;
if (consumeIfAttributeLParen()) {
// Custom C name.
Expand Down Expand Up @@ -3127,10 +3120,9 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
Attributes.add(new (Context) SILGenNameAttr(AsmName.value(), Raw, AtLoc,
AttrRange, /*Implicit=*/false));
else if (DK == DeclAttrKind::CDecl) {
bool underscored = AttrName.starts_with("_");
Attributes.add(new (Context) CDeclAttr(AsmName.value(), AtLoc,
AttrRange, /*Implicit=*/false,
/*isUnderscored*/underscored));
/*isUnderscored*/true));
} else if (DK == DeclAttrKind::Expose) {
for (auto *EA : Attributes.getAttributes<ExposeAttr>()) {
// A single declaration cannot have two @_exported attributes with
Expand Down
4 changes: 2 additions & 2 deletions test/PrintAsObjC/cdecl-enum-reference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
// REQUIRES: swift_feature_CDecl

//--- CoreLib.swift
@cdecl("CEnum")
@cdecl(CEnum)
public enum CEnum: CInt { case A, B }

//--- MiddleLib.swift
import CoreLib

@cdecl("CFunc")
@cdecl(CFunc)
public func CFunc(e: CEnum) {}
// CHECK: typedef SWIFT_ENUM_FWD_DECL(int, CEnum)
// CHECK: SWIFT_EXTERN void CFunc(SWIFT_ENUM_TAG CEnum e) SWIFT_NOEXCEPT;
Expand Down
20 changes: 10 additions & 10 deletions test/PrintAsObjC/cdecl-enums.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import Foundation
// CHECK-NEXT: }

/// Foo: A feer, a female feer.
@cdecl("FooComments") public enum FooComments: CInt {
@cdecl(FooComments) public enum FooComments: CInt {
/// Zim: A zeer, a female zeer.
case Zim
case Zang, Zung
Expand All @@ -67,7 +67,7 @@ import Foundation
// CHECK-NEXT: Zang = -219,
// CHECK-NEXT: Zung = -218,
// CHECK-NEXT: };
@cdecl("NegativeValues") enum NegativeValues: Int16 {
@cdecl(NegativeValues) enum NegativeValues: Int16 {
case Zang = -219, Zung

func methodNotExportedToC() {}
Expand All @@ -77,40 +77,40 @@ import Foundation
// CHECK-NEXT: SomeErrorBadness = 9001,
// CHECK-NEXT: SomeErrorWorseness = 9002,
// CHECK-NEXT: };
@cdecl("SomeError") enum SomeError: Int, Error {
@cdecl(SomeError) enum SomeError: Int, Error {
case Badness = 9001
case Worseness
}

// CHECK-LABEL: typedef SWIFT_ENUM_NAMED(ptrdiff_t, SomeOtherError, "SomeOtherError", closed) {
// CHECK-NEXT: SomeOtherErrorDomain = 0,
// CHECK-NEXT: };
@cdecl("SomeOtherError") enum SomeOtherError: Int, Error {
@cdecl(SomeOtherError) enum SomeOtherError: Int, Error {
case Domain
}

// CHECK-LABEL: typedef SWIFT_ENUM_NAMED(ptrdiff_t, ObjcErrorType, "SomeRenamedErrorType", closed) {
// CHECK-NEXT: ObjcErrorTypeBadStuff = 0,
// CHECK-NEXT: };
@cdecl("ObjcErrorType") enum SomeRenamedErrorType: Int, Error {
@cdecl(ObjcErrorType) enum SomeRenamedErrorType: Int, Error {
case BadStuff
}

@cdecl("acceptMemberImported") func acceptMemberImported(a: Wrapper.Raw, b: Wrapper.Enum, c: Wrapper.Options, d: Wrapper.Typedef, e: Wrapper.Anon, ee: Wrapper.Anon2) {}
@cdecl(acceptMemberImported) func acceptMemberImported(a: Wrapper.Raw, b: Wrapper.Enum, c: Wrapper.Options, d: Wrapper.Typedef, e: Wrapper.Anon, ee: Wrapper.Anon2) {}
// CHECK-LABEL: SWIFT_EXTERN void acceptMemberImported(enum MemberRaw a, enum MemberEnum b, MemberOptions c, enum MemberTypedef d, MemberAnon e, MemberAnon2 ee) SWIFT_NOEXCEPT;

@cdecl("acceptPlainEnum") func acceptPlainEnum(_: NSMalformedEnumMissingTypedef) {}
@cdecl(acceptPlainEnum) func acceptPlainEnum(_: NSMalformedEnumMissingTypedef) {}
// CHECK-LABEL: SWIFT_EXTERN void acceptPlainEnum(enum NSMalformedEnumMissingTypedef) SWIFT_NOEXCEPT;

@cdecl("acceptTopLevelImported") func acceptTopLevelImported(a: TopLevelRaw, b: TopLevelEnum, c: TopLevelOptions, d: TopLevelTypedef, e: TopLevelAnon) {}
@cdecl(acceptTopLevelImported) func acceptTopLevelImported(a: TopLevelRaw, b: TopLevelEnum, c: TopLevelOptions, d: TopLevelTypedef, e: TopLevelAnon) {}
// CHECK-LABEL: SWIFT_EXTERN void acceptTopLevelImported(enum TopLevelRaw a, TopLevelEnum b, TopLevelOptions c, TopLevelTypedef d, TopLevelAnon e) SWIFT_NOEXCEPT;

@cdecl("takeAndReturnEnumC") func takeAndReturnEnumC(_ foo: FooComments) -> NegativeValues {
@cdecl(takeAndReturnEnumC) func takeAndReturnEnumC(_ foo: FooComments) -> NegativeValues {
return .Zung
}
// CHECK-LABEL: SWIFT_EXTERN SWIFT_ENUM_TAG NegativeValues takeAndReturnEnumC(SWIFT_ENUM_TAG FooComments foo) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;

@cdecl("takeAndReturnRenamedEnum") func takeAndReturnRenamedEnum(_ foo: EnumNamed) -> EnumNamed {
@cdecl(takeAndReturnRenamedEnum) func takeAndReturnRenamedEnum(_ foo: EnumNamed) -> EnumNamed {
return .A
}
// CHECK-LABEL: SWIFT_EXTERN SWIFT_ENUM_TAG ObjcEnumNamed takeAndReturnRenamedEnum(SWIFT_ENUM_TAG ObjcEnumNamed foo) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;
Expand Down
4 changes: 2 additions & 2 deletions test/PrintAsObjC/cdecl-includes-with-objc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ import Foundation
// CHECK: extern "C" {
// CHECK: #endif

@cdecl("get_int_alias")
@cdecl(get_int_alias)
public func getIntAlias() -> IntFromCFramework { 42 }
// CHECK: SWIFT_EXTERN IntFromCFramework get_int_alias(void) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;

@cdecl("imports_cgpoint")
@cdecl(imports_cgpoint)
public func importsCGPoint(pt: CGPoint) { }
// CHECK: SWIFT_EXTERN void imports_cgpoint(CGPoint pt) SWIFT_NOEXCEPT;

Expand Down
6 changes: 3 additions & 3 deletions test/PrintAsObjC/cdecl-includes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,16 @@ import CModule
// CHECK: extern "C" {
// CHECK: #endif

@cdecl("mirror_struct")
@cdecl(mirror_struct)
public func a_mirrorStruct(_ a: CStruct) -> CStruct { a }
// CHECK: SWIFT_EXTERN struct CStruct mirror_struct(struct CStruct a) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;

@cdecl("mirror_union")
@cdecl(mirror_union)
public func b_mirrorStruct(_ a: CUnion) -> CUnion { a }
// CHECK: SWIFT_EXTERN union CUnion mirror_union(union CUnion a) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;


@cdecl("TKGetDefaultToastSetting")
@cdecl(TKGetDefaultToastSetting)
public func c_defaultToastSetting() -> TKTimeSetting { TKTimeSettingNormal } // It would be nice to import TKTimeSettingNormal as a member.
// CHECK: SWIFT_EXTERN TKTimeSetting TKGetDefaultToastSetting(void) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;

Expand Down
20 changes: 10 additions & 10 deletions test/PrintAsObjC/cdecl-official.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,30 +53,30 @@ func a0_simple(x: Int, bar y: Int) -> Int { return x }
func a1_defaultName(x: Int) -> Int { return x }
// CHECK-LABEL: SWIFT_EXTERN ptrdiff_t a1_defaultName(ptrdiff_t x) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;

@cdecl("primitiveTypes")
@cdecl(primitiveTypes)
public func b_primitiveTypes(i: Int, ci: CInt, l: CLong, c: CChar, f: Float, d: Double, b: Bool) {}
// CHECK-LABEL: SWIFT_EXTERN void primitiveTypes(ptrdiff_t i, int ci, long l, char c, float f, double d, bool b) SWIFT_NOEXCEPT;

@cdecl("has_keyword_arg_names")
@cdecl(has_keyword_arg_names)
func c_keywordArgNames(auto: Int, union: Int) {}
// CHECK-LABEL: SWIFT_EXTERN void has_keyword_arg_names(ptrdiff_t auto_, ptrdiff_t union_) SWIFT_NOEXCEPT;

@cdecl("return_never")
@cdecl(return_never)
func d_returnNever() -> Never { fatalError() }
// CHECK-LABEL: SWIFT_EXTERN void return_never(void) SWIFT_NOEXCEPT SWIFT_NORETURN;

/// Pointer types
// CHECK: /// Pointer types

@cdecl("pointers")
@cdecl(pointers)
func f_pointers(_ x: UnsafeMutablePointer<Int>,
y: UnsafePointer<Int>,
z: UnsafeMutableRawPointer,
w: UnsafeRawPointer,
u: OpaquePointer) {}
// CHECK: SWIFT_EXTERN void pointers(ptrdiff_t * _Nonnull x, ptrdiff_t const * _Nonnull y, void * _Nonnull z, void const * _Nonnull w, void * _Nonnull u) SWIFT_NOEXCEPT;

@cdecl("nullable_pointers")
@cdecl(nullable_pointers)
func g_nullablePointers(_ x: UnsafeMutableRawPointer,
y: UnsafeMutableRawPointer?,
z: UnsafeMutableRawPointer!) {}
Expand All @@ -87,23 +87,23 @@ func g_nullablePointers(_ x: UnsafeMutableRawPointer,
@cdecl
enum CEnum: CInt { case A, B }

@cdecl("CEnumRenamed_CName")
@cdecl(CEnumRenamed_CName)
enum CEnumRenamed: CLong { case A, B }

@cdecl("use_enum")
@cdecl(use_enum)
func h_useCEnum(e: CEnum) -> CEnum { return e }
// CHECK: SWIFT_EXTERN SWIFT_ENUM_TAG CEnum use_enum(SWIFT_ENUM_TAG CEnum e) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;

@cdecl("use_enum_renamed")
@cdecl(use_enum_renamed)
func i_useCEnumLong(e: CEnumRenamed) -> CEnumRenamed { return e }
// CHECK: SWIFT_EXTERN SWIFT_ENUM_TAG CEnumRenamed_CName use_enum_renamed(SWIFT_ENUM_TAG CEnumRenamed_CName e) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;

@cdecl("use_enum_late")
@cdecl(use_enum_late)
func j_useCEnumChar(e: zCEnumDefinedLate) -> zCEnumDefinedLate { return e }
// CHECK: SWIFT_EXTERN SWIFT_ENUM_TAG zCEnumDefinedLate use_enum_late(SWIFT_ENUM_TAG zCEnumDefinedLate e) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;

/// Declare this enum late in the source file and in alphabetical order.
@cdecl("zCEnumDefinedLate")
@cdecl(zCEnumDefinedLate)
enum zCEnumDefinedLate: CChar { case A, B }

// CHECK: #if defined(__cplusplus)
Expand Down
2 changes: 1 addition & 1 deletion test/PrintAsObjC/cdecl-with-objc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
// REQUIRES: swift_feature_CDecl
// REQUIRES: objc_interop

@cdecl("cFunc")
@cdecl
func cFunc() { }
// CHECK: cFunc
// CHECK-NOT: cFunc
Expand Down
Loading