Skip to content

Commit 2601ff4

Browse files
committed
Parser: Accept @cdecl with an indentifier for the C name
Begin accepting the attribute in the form of `@cdecl(cName)`, using an identifier instead of a string. For ease of landing this change we still accept the string form. We should stop accepting it before making this feature available in production.
1 parent b8b13d8 commit 2601ff4

File tree

4 files changed

+61
-4
lines changed

4 files changed

+61
-4
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,6 +1532,9 @@ ERROR(attr_expected_comma,none,
15321532
ERROR(attr_expected_string_literal,none,
15331533
"expected string literal in '%0' attribute", (StringRef))
15341534

1535+
ERROR(attr_expected_cname,none,
1536+
"expected C identifier in '%0' attribute", (StringRef))
1537+
15351538
ERROR(attr_expected_option_such_as,none,
15361539
"expected '%0' option such as '%1'", (StringRef, StringRef))
15371540

lib/Parse/ParseDecl.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3014,7 +3014,45 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
30143014
break;
30153015
}
30163016

3017-
case DeclAttrKind::CDecl:
3017+
case DeclAttrKind::CDecl: {
3018+
if (!AttrName.starts_with("_") &&
3019+
3020+
// Backwards support for @cdecl("stringId"). Remove before enabling in
3021+
// production so we accept only the identifier format.
3022+
lookahead<bool>(1, [&](CancellableBacktrackingScope &) {
3023+
return Tok.isNot(tok::string_literal);
3024+
})) {
3025+
3026+
std::optional<StringRef> CName;
3027+
if (consumeIfAttributeLParen()) {
3028+
// Custom C name.
3029+
if (Tok.isNot(tok::identifier)) {
3030+
diagnose(Loc, diag::attr_expected_cname, AttrName);
3031+
return makeParserSuccess();
3032+
}
3033+
3034+
CName = Tok.getText();
3035+
consumeToken(tok::identifier);
3036+
AttrRange = SourceRange(Loc, Tok.getRange().getStart());
3037+
3038+
if (!consumeIf(tok::r_paren)) {
3039+
diagnose(Loc, diag::attr_expected_rparen, AttrName,
3040+
DeclAttribute::isDeclModifier(DK));
3041+
return makeParserSuccess();
3042+
}
3043+
} else {
3044+
AttrRange = SourceRange(Loc);
3045+
}
3046+
3047+
Attributes.add(new (Context) CDeclAttr(CName.value_or(StringRef()), AtLoc,
3048+
AttrRange, /*Implicit=*/false,
3049+
/*isUnderscored*/false));
3050+
break;
3051+
}
3052+
3053+
// Leave legacy @_cdecls to the logic expecting a string.
3054+
LLVM_FALLTHROUGH;
3055+
}
30183056
case DeclAttrKind::Expose:
30193057
case DeclAttrKind::SILGenName: {
30203058
if (!consumeIfAttributeLParen()) {

test/PrintAsObjC/cdecl-official.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
// CHECK: #endif
2929

3030
/// My documentation
31-
@cdecl("simple")
32-
func a_simple(x: Int, bar y: Int) -> Int { return x }
31+
@cdecl(simple)
32+
func a0_simple(x: Int, bar y: Int) -> Int { return x }
3333
// CHECK-LABEL: // My documentation
3434
// CHECK-LABEL: SWIFT_EXTERN ptrdiff_t simple(ptrdiff_t x, ptrdiff_t y) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;
3535

test/attr/attr_cdecl_official.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,23 @@
66

77
// REQUIRES: swift_feature_CDecl
88

9-
@cdecl("cdecl_foo") func foo(x: Int) -> Int { return x }
9+
@cdecl(cdecl_foo) func foo(x: Int) -> Int { return x }
10+
11+
@cdecl(not an identifier) func invalidName() {}
12+
// expected-error @-1 {{expected ')' in 'cdecl' attribute}}
13+
// expected-error @-2 {{expected declaration}}
14+
15+
@cdecl() func emptyParen() {}
16+
// expected-error @-1 {{expected C identifier in 'cdecl' attribute}}
17+
// expected-error @-2 {{expected declaration}}
18+
19+
@cdecl(42) func aNumber() {}
20+
// expected-error @-1 {{expected C identifier in 'cdecl' attribute}}
21+
// expected-error @-2 {{expected declaration}}
22+
23+
@cdecl(a:selector:) func selectordName() {}
24+
// expected-error @-1 {{expected ')' in 'cdecl' attribute}}
25+
// expected-error @-2 {{expected declaration}}
1026

1127
@cdecl("") // expected-error{{@cdecl symbol name cannot be empty}}
1228
func emptyName(x: Int) -> Int { return x }

0 commit comments

Comments
 (0)