Skip to content
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

Initial implementation of a @_cdecl attribute to export top-level functions to C #3

Closed
wants to merge 1 commit into from
Closed
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
4 changes: 4 additions & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ SIMPLE_DECL_ATTR(warn_unqualified_access, WarnUnqualifiedAccess,
SIMPLE_DECL_ATTR(_show_in_interface, ShowInInterface,
OnProtocol | UserInaccessible, 62)

DECL_ATTR(_cdecl, CDecl,
OnFunc | LongAttribute | UserInaccessible, 63)


#undef TYPE_ATTR
#undef DECL_ATTR_ALIAS
#undef SIMPLE_DECL_ATTR
Expand Down
18 changes: 18 additions & 0 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,24 @@ class SILGenNameAttr : public DeclAttribute {
}
};

/// Defines the @_cdecl attribute.
class CDeclAttr : public DeclAttribute {
public:
CDeclAttr(StringRef Name, SourceLoc AtLoc, SourceRange Range, bool Implicit)
: DeclAttribute(DAK_CDecl, AtLoc, Range, Implicit),
Name(Name) {}

CDeclAttr(StringRef Name, bool Implicit)
: CDeclAttr(Name, SourceLoc(), SourceRange(), /*Implicit=*/true) {}

/// The symbol name.
const StringRef Name;

static bool classof(const DeclAttribute *DA) {
return DA->getKind() == DAK_CDecl;
}
};

/// Defines the @_semantics attribute.
class SemanticsAttr : public DeclAttribute {
public:
Expand Down
10 changes: 9 additions & 1 deletion include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,14 @@ ERROR(no_objc_tagged_pointer_not_class_protocol,none,
ERROR(swift_native_objc_runtime_base_not_on_root_class,none,
"@_swift_native_objc_runtime_base_not_on_root_class can only be applied "
"to root classes", ())

ERROR(cdecl_not_at_top_level,none,
"@_cdecl can only be applied to global functions", ())
ERROR(cdecl_empty_name,none,
"@_cdecl symbol name cannot be empty", ())
ERROR(cdecl_throws,none,
"raising errors from @_cdecl functions is not supported", ())

ERROR(attr_methods_only,none,
"only methods can be declared %0", (DeclAttribute))
ERROR(access_control_in_protocol,none,
Expand Down Expand Up @@ -2487,7 +2495,7 @@ ERROR(objc_enum_case_multi,none,
"'@objc' enum case declaration defines multiple enum cases with the same Objective-C name", ())

// If you change this, also change enum ObjCReason
#define OBJC_ATTR_SELECT "select{marked dynamic|marked @objc|marked @IBOutlet|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override}"
#define OBJC_ATTR_SELECT "select{marked @_cdecl|marked dynamic|marked @objc|marked @IBOutlet|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override}"

ERROR(objc_invalid_on_var,none,
"property cannot be %" OBJC_ATTR_SELECT "0 "
Expand Down
12 changes: 10 additions & 2 deletions include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const unsigned char MODULE_DOC_SIGNATURE[] = { 0xE2, 0x9C, 0xA8, 0x07 };

/// Serialized module format major version number.
///
/// Always 0 for Swift 1.0.
/// Always 0 for Swift 1.x and 2.x.
const uint16_t VERSION_MAJOR = 0;

/// Serialized module format minor version number.
Expand All @@ -53,7 +53,8 @@ const uint16_t VERSION_MAJOR = 0;
/// in source control, you should also update the comment to briefly
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
const uint16_t VERSION_MINOR = 239; // multiple results for SILFunctionType
/// describe what change you made.
const uint16_t VERSION_MINOR = 240; // Last change: @_cdecl

using DeclID = PointerEmbeddedInt<unsigned, 31>;
using DeclIDField = BCFixed<31>;
Expand Down Expand Up @@ -1223,6 +1224,13 @@ namespace decls_block {
BCFixed<1>, // implicit flag
BCBlob // _silgen_name
>;

using CDeclDeclAttrLayout = BCRecordLayout<
CDecl_DECL_ATTR,
BCFixed<1>, // implicit flag
BCBlob // _silgen_name
>;


using AlignmentDeclAttrLayout = BCRecordLayout<
Alignment_DECL_ATTR,
Expand Down
5 changes: 4 additions & 1 deletion lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1908,7 +1908,10 @@ void AbstractFunctionDecl::setForeignErrorConvention(

Optional<ForeignErrorConvention>
AbstractFunctionDecl::getForeignErrorConvention() const {
if (!isObjC() || !isBodyThrowing()) return None;
if (!isObjC() && !getAttrs().hasAttribute<CDeclAttr>())
return None;
if (!isBodyThrowing())
return None;
auto &conventionsMap = getASTContext().Impl.ForeignErrorConventions;
auto it = conventionsMap.find(this);
if (it == conventionsMap.end()) return None;
Expand Down
5 changes: 3 additions & 2 deletions lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2200,8 +2200,9 @@ struct ASTNodeBase {};
abort();
}

if (AFD->getForeignErrorConvention() && !AFD->isObjC()) {
Out << "foreign error convention on non-@objc function\n";
if (AFD->getForeignErrorConvention()
&& !AFD->isObjC() && !AFD->getAttrs().hasAttribute<CDeclAttr>()) {
Out << "foreign error convention on non-@objc, non-@_cdecl function\n";
AFD->dump(Out);
abort();
}
Expand Down
7 changes: 7 additions & 0 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,11 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options)
if (cast<AutoClosureAttr>(this)->isEscaping())
Printer << "(escaping)";
break;

case DAK_CDecl:
Printer << "@_cdecl(\"" << cast<CDeclAttr>(this)->Name << "\")";
break;

case DAK_ObjC: {
Printer.printAttrName("@objc");
llvm::SmallString<32> scratch;
Expand Down Expand Up @@ -487,6 +492,8 @@ StringRef DeclAttribute::getAttrName() const {
return "_silgen_name";
case DAK_Alignment:
return "_alignment";
case DAK_CDecl:
return "_cdecl";
case DAK_SwiftNativeObjCRuntimeBase:
return "_swift_native_objc_runtime_base";
case DAK_Semantics:
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/Linking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ void LinkEntity::mangle(raw_ostream &buffer) const {

// entity ::= declaration // other declaration
case Kind::Function:
// As a special case, functions can have external asm names.
// As a special case, functions can have manually mangled names.
if (auto AsmA = getDecl()->getAttrs().getAttribute<SILGenNameAttr>()) {
mangler.append(AsmA->Name);
return mangler.finalize(buffer);
Expand Down
12 changes: 10 additions & 2 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
break;
}

case DAK_CDecl:
case DAK_SILGenName: {
if (!consumeIf(tok::l_paren)) {
diagnose(Loc, diag::attr_expected_lparen, AttrName,
Expand Down Expand Up @@ -601,9 +602,16 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
diagnose(Loc, diag::attr_only_at_non_local_scope, AttrName);
}

if (!DiscardAttribute)
Attributes.add(new (Context) SILGenNameAttr(AsmName.getValue(), AtLoc,
if (!DiscardAttribute) {
if (DK == DAK_SILGenName)
Attributes.add(new (Context) SILGenNameAttr(AsmName.getValue(), AtLoc,
AttrRange, /*Implicit=*/false));
else if (DK == DAK_CDecl)
Attributes.add(new (Context) CDeclAttr(AsmName.getValue(), AtLoc,
AttrRange, /*Implicit=*/false));
else
llvm_unreachable("out of sync with switch");
}

break;
}
Expand Down
Loading