mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
This commit is contained in:
@@ -1532,6 +1532,9 @@ ERROR(attr_expected_comma,none,
|
||||
ERROR(attr_expected_string_literal,none,
|
||||
"expected string literal in '%0' attribute", (StringRef))
|
||||
|
||||
ERROR(attr_expected_cname,none,
|
||||
"expected C identifier in '%0' attribute", (StringRef))
|
||||
|
||||
ERROR(attr_expected_option_such_as,none,
|
||||
"expected '%0' option such as '%1'", (StringRef, StringRef))
|
||||
|
||||
|
||||
@@ -3014,7 +3014,45 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
|
||||
break;
|
||||
}
|
||||
|
||||
case DeclAttrKind::CDecl:
|
||||
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);
|
||||
})) {
|
||||
|
||||
std::optional<StringRef> CName;
|
||||
if (consumeIfAttributeLParen()) {
|
||||
// Custom C name.
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
diagnose(Loc, diag::attr_expected_cname, AttrName);
|
||||
return makeParserSuccess();
|
||||
}
|
||||
|
||||
CName = Tok.getText();
|
||||
consumeToken(tok::identifier);
|
||||
AttrRange = SourceRange(Loc, Tok.getRange().getStart());
|
||||
|
||||
if (!consumeIf(tok::r_paren)) {
|
||||
diagnose(Loc, diag::attr_expected_rparen, AttrName,
|
||||
DeclAttribute::isDeclModifier(DK));
|
||||
return makeParserSuccess();
|
||||
}
|
||||
} else {
|
||||
AttrRange = SourceRange(Loc);
|
||||
}
|
||||
|
||||
Attributes.add(new (Context) CDeclAttr(CName.value_or(StringRef()), AtLoc,
|
||||
AttrRange, /*Implicit=*/false,
|
||||
/*isUnderscored*/false));
|
||||
break;
|
||||
}
|
||||
|
||||
// Leave legacy @_cdecls to the logic expecting a string.
|
||||
LLVM_FALLTHROUGH;
|
||||
}
|
||||
case DeclAttrKind::Expose:
|
||||
case DeclAttrKind::SILGenName: {
|
||||
if (!consumeIfAttributeLParen()) {
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
// CHECK: #endif
|
||||
|
||||
/// My documentation
|
||||
@cdecl("simple")
|
||||
func a_simple(x: Int, bar y: Int) -> Int { return x }
|
||||
@cdecl(simple)
|
||||
func a0_simple(x: Int, bar y: Int) -> Int { return x }
|
||||
// CHECK-LABEL: // My documentation
|
||||
// CHECK-LABEL: SWIFT_EXTERN ptrdiff_t simple(ptrdiff_t x, ptrdiff_t y) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;
|
||||
|
||||
|
||||
@@ -6,7 +6,23 @@
|
||||
|
||||
// REQUIRES: swift_feature_CDecl
|
||||
|
||||
@cdecl("cdecl_foo") func foo(x: Int) -> Int { return x }
|
||||
@cdecl(cdecl_foo) func foo(x: Int) -> Int { return x }
|
||||
|
||||
@cdecl(not an identifier) func invalidName() {}
|
||||
// expected-error @-1 {{expected ')' in 'cdecl' attribute}}
|
||||
// expected-error @-2 {{expected declaration}}
|
||||
|
||||
@cdecl() func emptyParen() {}
|
||||
// expected-error @-1 {{expected C identifier in 'cdecl' attribute}}
|
||||
// expected-error @-2 {{expected declaration}}
|
||||
|
||||
@cdecl(42) func aNumber() {}
|
||||
// expected-error @-1 {{expected C identifier in 'cdecl' attribute}}
|
||||
// expected-error @-2 {{expected declaration}}
|
||||
|
||||
@cdecl(a:selector:) func selectordName() {}
|
||||
// expected-error @-1 {{expected ')' in 'cdecl' attribute}}
|
||||
// expected-error @-2 {{expected declaration}}
|
||||
|
||||
@cdecl("") // expected-error{{@cdecl symbol name cannot be empty}}
|
||||
func emptyName(x: Int) -> Int { return x }
|
||||
|
||||
Reference in New Issue
Block a user