Skip to content

Commit 405a84e

Browse files
authored
Merge pull request #80744 from xymus/cdecl-global-function-checking
Sema: Intro experimental @cdecl and basic C compatibility check
2 parents f89dcf7 + a6beaf8 commit 405a84e

28 files changed

+329
-114
lines changed

include/swift/AST/Attr.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -690,22 +690,29 @@ class SectionAttr : public DeclAttribute {
690690
/// Defines the @_cdecl attribute.
691691
class CDeclAttr : public DeclAttribute {
692692
public:
693-
CDeclAttr(StringRef Name, SourceLoc AtLoc, SourceRange Range, bool Implicit)
694-
: DeclAttribute(DeclAttrKind::CDecl, AtLoc, Range, Implicit), Name(Name) {
693+
CDeclAttr(StringRef Name, SourceLoc AtLoc, SourceRange Range, bool Implicit,
694+
bool Underscored)
695+
: DeclAttribute(DeclAttrKind::CDecl, AtLoc, Range, Implicit),
696+
Name(Name), Underscored(Underscored) {
695697
}
696698

697-
CDeclAttr(StringRef Name, bool Implicit)
698-
: CDeclAttr(Name, SourceLoc(), SourceRange(), Implicit) {}
699+
CDeclAttr(StringRef Name, bool Implicit, bool Underscored)
700+
: CDeclAttr(Name, SourceLoc(), SourceRange(), Implicit, Underscored) {}
699701

700702
/// The symbol name.
701703
const StringRef Name;
702704

705+
/// Is this the version of the attribute that's underscored?
706+
/// Used to preserve retro compatibility with early adopters.
707+
const bool Underscored;
708+
703709
static bool classof(const DeclAttribute *DA) {
704710
return DA->getKind() == DeclAttrKind::CDecl;
705711
}
706712

707713
CDeclAttr *clone(ASTContext &ctx) const {
708-
return new (ctx) CDeclAttr(Name, AtLoc, Range, isImplicit());
714+
return new (ctx) CDeclAttr(Name, AtLoc, Range, isImplicit(),
715+
Underscored);
709716
}
710717

711718
bool isEquivalent(const CDeclAttr *other, Decl *attachedTo) const {

include/swift/AST/Decl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8134,6 +8134,11 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
81348134
/// instance method.
81358135
bool isObjCInstanceMethod() const;
81368136

8137+
/// Get the foreign language targeted by a @cdecl-style attribute, if any.
8138+
/// Used to abstract away the change in meaning of @cdecl vs @_cdecl while
8139+
/// formalizing the attribute.
8140+
std::optional<ForeignLanguage> getCDeclKind() const;
8141+
81378142
/// Determine whether the name of an argument is an API name by default
81388143
/// depending on the function context.
81398144
bool argumentNameIsAPIByDefault() const;

include/swift/AST/DeclAttr.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ DECL_ATTR(_cdecl, CDecl,
368368
OnFunc | OnAccessor,
369369
LongAttribute | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
370370
63)
371+
DECL_ATTR_ALIAS(cdecl, CDecl)
371372

372373
SIMPLE_DECL_ATTR(usableFromInline, UsableFromInline,
373374
OnAbstractFunction | OnVar | OnSubscript | OnNominalType | OnTypeAlias,

include/swift/AST/DiagnosticsSema.def

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,11 +2044,14 @@ WARNING(wrap_objc_implementation_will_become_error,none,
20442044
(DiagnosticInfo *))
20452045

20462046
ERROR(cdecl_not_at_top_level,none,
2047-
"@_cdecl can only be applied to global functions", ())
2047+
"%0 can only be applied to global functions", (DeclAttribute))
20482048
ERROR(cdecl_empty_name,none,
2049-
"@_cdecl symbol name cannot be empty", ())
2049+
"%0 symbol name cannot be empty", (DeclAttribute))
20502050
ERROR(cdecl_throws,none,
2051-
"raising errors from @_cdecl functions is not supported", ())
2051+
"raising errors from %0 functions is not supported", (DeclAttribute))
2052+
ERROR(cdecl_feature_required,none,
2053+
"@cdecl requires '-enable-experimental-feature CDecl'",
2054+
())
20522055

20532056
// @_used and @_section
20542057
ERROR(section_linkage_markers_disabled,none,
@@ -6499,7 +6502,10 @@ ERROR(objc_cannot_infer_name_raw_identifier,none,
64996502
(const ValueDecl *))
65006503

65016504
// If you change this, also change enum ObjCReason
6502-
#define OBJC_ATTR_SELECT "select{marked @_cdecl|marked dynamic|marked @objc|marked @objcMembers|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)|in an @objc @implementation extension of a class (without final or @nonobjc)|marked @objc by an access note}"
6505+
#define OBJC_ATTR_SELECT "select{marked @cdecl|marked @_cdecl|marked dynamic|marked @objc|marked @objcMembers|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)|in an @objc @implementation extension of a class (without final or @nonobjc)|marked @objc by an access note}"
6506+
6507+
// Keep aligned with enum ForeignLanguage
6508+
#define FOREIGN_LANG_SELECT "select{C|Objective-C}"
65036509

65046510
ERROR(objc_invalid_on_var,none,
65056511
"property cannot be %" OBJC_ATTR_SELECT "0 "
@@ -6579,17 +6585,21 @@ ERROR(objc_invalid_on_func_variadic,none,
65796585
"method cannot be %" OBJC_ATTR_SELECT "0 because it has a variadic "
65806586
"parameter", (unsigned))
65816587
ERROR(objc_invalid_on_func_inout,none,
6582-
"method cannot be %" OBJC_ATTR_SELECT "0 because inout "
6583-
"parameters cannot be represented in Objective-C", (unsigned))
6588+
"%kindonly0 cannot be %" OBJC_ATTR_SELECT "1 because inout "
6589+
"parameters cannot be represented in %" FOREIGN_LANG_SELECT "2",
6590+
(const AbstractFunctionDecl*, unsigned, unsigned))
65846591
ERROR(objc_invalid_on_func_param_type,none,
6585-
"method cannot be %" OBJC_ATTR_SELECT "1 because the type of the "
6586-
"parameter %0 cannot be represented in Objective-C", (unsigned, unsigned))
6592+
"%kindonly0 cannot be %" OBJC_ATTR_SELECT "2 because the type of the "
6593+
"parameter %1 cannot be represented in %" FOREIGN_LANG_SELECT "3",
6594+
(const AbstractFunctionDecl*, unsigned, unsigned, unsigned))
65876595
ERROR(objc_invalid_on_func_single_param_type,none,
6588-
"method cannot be %" OBJC_ATTR_SELECT "0 because the type of the "
6589-
"parameter cannot be represented in Objective-C", (unsigned))
6596+
"%kindonly0 cannot be %" OBJC_ATTR_SELECT "1 because the type of the "
6597+
"parameter cannot be represented in %" FOREIGN_LANG_SELECT "2",
6598+
(const AbstractFunctionDecl*, unsigned, unsigned))
65906599
ERROR(objc_invalid_on_func_result_type,none,
6591-
"method cannot be %" OBJC_ATTR_SELECT "0 because its result type "
6592-
"cannot be represented in Objective-C", (unsigned))
6600+
"%kindonly0 cannot be %" OBJC_ATTR_SELECT "1 because its result type "
6601+
"cannot be represented in %" FOREIGN_LANG_SELECT "2",
6602+
(const AbstractFunctionDecl*, unsigned, unsigned))
65936603
ERROR(objc_invalid_on_foreign_class,none,
65946604
"method cannot be %" OBJC_ATTR_SELECT "0 because Core Foundation "
65956605
"types are not classes in Objective-C", (unsigned))
@@ -6715,6 +6725,7 @@ ERROR(nonobjc_not_allowed,none,
67156725
#undef OBJC_DIAG_SELECT_2
67166726
#undef OBJC_DIAG_SELECT
67176727
#undef OBJC_ATTR_SELECT
6728+
#undef FOREIGN_LANG_SELECT
67186729

67196730
//------------------------------------------------------------------------------
67206731
// MARK: @exclusivity

include/swift/AST/TypeCheckRequests.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4853,6 +4853,25 @@ class TypeCheckObjCImplementationRequest
48534853
bool isCached() const { return true; }
48544854
};
48554855

4856+
/// Check @cdecl-style attributes for compatibility with the foreign language.
4857+
class TypeCheckCDeclAttributeRequest
4858+
: public SimpleRequest<TypeCheckCDeclAttributeRequest,
4859+
evaluator::SideEffect(FuncDecl *FD,
4860+
CDeclAttr *attr),
4861+
RequestFlags::Cached> {
4862+
public:
4863+
using SimpleRequest::SimpleRequest;
4864+
4865+
private:
4866+
friend SimpleRequest;
4867+
4868+
evaluator::SideEffect
4869+
evaluate(Evaluator &evaluator, FuncDecl *FD, CDeclAttr *attr) const;
4870+
4871+
public:
4872+
bool isCached() const { return true; }
4873+
};
4874+
48564875
void simple_display(llvm::raw_ostream &out, ASTNode node);
48574876
void simple_display(llvm::raw_ostream &out, Type value);
48584877
void simple_display(llvm::raw_ostream &out, const TypeRepr *TyR);

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,9 @@ SWIFT_REQUEST(TypeChecker, IsNonUserModuleRequest,
550550
SWIFT_REQUEST(TypeChecker, TypeCheckObjCImplementationRequest,
551551
unsigned(ExtensionDecl *),
552552
Cached, NoLocationInfo)
553+
SWIFT_REQUEST(TypeChecker, TypeCheckCDeclAttributeRequest,
554+
evaluator::SideEffect(FuncDecl *, CDeclAttr *),
555+
Cached, NoLocationInfo)
553556
SWIFT_REQUEST(TypeChecker, HasInitAccessorRequest,
554557
bool(AbstractStorageDecl *), Cached,
555558
NoLocationInfo)

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,9 @@ EXPERIMENTAL_FEATURE(ClosureBodyMacro, true)
514514
/// Allow declarations of Swift runtime symbols using @_silgen_name.
515515
EXPERIMENTAL_FEATURE(AllowRuntimeSymbolDeclarations, true)
516516

517+
/// Allow use of `@cdecl`
518+
EXPERIMENTAL_FEATURE(CDecl, false)
519+
517520
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
518521
#undef EXPERIMENTAL_FEATURE
519522
#undef UPCOMING_FEATURE

lib/AST/Attr.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1783,7 +1783,9 @@ StringRef DeclAttribute::getAttrName() const {
17831783
case DeclAttrKind::Alignment:
17841784
return "_alignment";
17851785
case DeclAttrKind::CDecl:
1786-
return "_cdecl";
1786+
if (cast<CDeclAttr>(this)->Underscored)
1787+
return "_cdecl";
1788+
return "cdecl";
17871789
case DeclAttrKind::SwiftNativeObjCRuntimeBase:
17881790
return "_swift_native_objc_runtime_base";
17891791
case DeclAttrKind::Semantics:

lib/AST/Bridging/DeclAttributeBridging.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ BridgedCDeclAttr BridgedCDeclAttr_createParsed(BridgedASTContext cContext,
250250
BridgedStringRef cName) {
251251
return new (cContext.unbridged())
252252
CDeclAttr(cName.unbridged(), cAtLoc.unbridged(), cRange.unbridged(),
253-
/*Implicit=*/false);
253+
/*Implicit=*/false, /*Underscored*/true);
254254
}
255255

256256
BridgedCustomAttr BridgedCustomAttr_createParsed(

lib/AST/Decl.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10520,6 +10520,15 @@ bool AbstractFunctionDecl::isObjCInstanceMethod() const {
1052010520
return isInstanceMember() || isa<ConstructorDecl>(this);
1052110521
}
1052210522

10523+
std::optional<ForeignLanguage> AbstractFunctionDecl::getCDeclKind() const {
10524+
auto attr = getAttrs().getAttribute<CDeclAttr>();
10525+
if (!attr)
10526+
return std::nullopt;
10527+
10528+
return attr->Underscored ? ForeignLanguage::ObjectiveC
10529+
: ForeignLanguage::C;
10530+
}
10531+
1052310532
bool AbstractFunctionDecl::needsNewVTableEntry() const {
1052410533
auto &ctx = getASTContext();
1052510534
return evaluateOrDefault(

0 commit comments

Comments
 (0)