Skip to content

Commit 2252154

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 9dcbd31 commit 2252154

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
@@ -1529,6 +1529,9 @@ ERROR(attr_expected_comma,none,
15291529
ERROR(attr_expected_string_literal,none,
15301530
"expected string literal in '%0' attribute", (StringRef))
15311531

1532+
ERROR(attr_expected_cname,none,
1533+
"expected C identifier in '%0' attribute", (StringRef))
1534+
15321535
ERROR(attr_expected_option_such_as,none,
15331536
"expected '%0' option such as '%1'", (StringRef, StringRef))
15341537

lib/Parse/ParseDecl.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2988,7 +2988,45 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
29882988
break;
29892989
}
29902990

2991-
case DeclAttrKind::CDecl:
2991+
case DeclAttrKind::CDecl: {
2992+
if (!AttrName.starts_with("_") &&
2993+
2994+
// Backwards support for @cdecl("stringId"). Remove before enabling in
2995+
// production so we accept only the identifier format.
2996+
lookahead<bool>(1, [&](CancellableBacktrackingScope &) {
2997+
return Tok.isNot(tok::string_literal);
2998+
})) {
2999+
3000+
std::optional<StringRef> CName;
3001+
if (consumeIfAttributeLParen()) {
3002+
// Custom C name.
3003+
if (Tok.isNot(tok::identifier)) {
3004+
diagnose(Loc, diag::attr_expected_cname, AttrName);
3005+
return makeParserSuccess();
3006+
}
3007+
3008+
CName = Tok.getText();
3009+
consumeToken(tok::identifier);
3010+
AttrRange = SourceRange(Loc, Tok.getRange().getStart());
3011+
3012+
if (!consumeIf(tok::r_paren)) {
3013+
diagnose(Loc, diag::attr_expected_rparen, AttrName,
3014+
DeclAttribute::isDeclModifier(DK));
3015+
return makeParserSuccess();
3016+
}
3017+
} else {
3018+
AttrRange = SourceRange(Loc);
3019+
}
3020+
3021+
Attributes.add(new (Context) CDeclAttr(CName.value_or(StringRef()), AtLoc,
3022+
AttrRange, /*Implicit=*/false,
3023+
/*isUnderscored*/false));
3024+
break;
3025+
}
3026+
3027+
// Leave legacy @_cdecls to the logic expecting a string.
3028+
LLVM_FALLTHROUGH;
3029+
}
29923030
case DeclAttrKind::Expose:
29933031
case DeclAttrKind::SILGenName: {
29943032
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)