Skip to content

Commit 4f0e3bf

Browse files
Merge pull request #69207 from kateinoigakukun/yt/cdecl-without-body
Introduce `@extern(c)` to declare C function without Clang module
2 parents 7b5db49 + 6947993 commit 4f0e3bf

32 files changed

+734
-87
lines changed

docs/ReferenceGuides/UnderscoredAttributes.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,18 +437,34 @@ the export name.
437437

438438
It's the equivalent of clang's `__attribute__((export_name))`.
439439

440-
## `@_extern(<language>)`
440+
## `@extern(<language>)`
441441

442442
Indicates that a particular declaration should be imported
443443
from the external environment.
444444

445-
### `@_extern(wasm, module: <"moduleName">, name: <"fieldName">)`
445+
### `@extern(wasm, module: <"moduleName">, name: <"fieldName">)`
446446

447447
Indicates that a particular declaration should be imported
448448
through WebAssembly's import interface.
449449

450450
It's the equivalent of clang's `__attribute__((import_module("module"), import_name("field")))`.
451451

452+
### `@extern(c, [, <"cName">])`
453+
454+
Indicates that a particular declaration should refer to a
455+
C declaration with the given name. If the optional "cName"
456+
string is not specified, the Swift function name is used
457+
without Swift name mangling. Platform-specific mangling
458+
rules (leading underscore on Darwin) are still applied.
459+
460+
Similar to `@_cdecl`, but this attribute is used to reference
461+
C declarations from Swift, while `@_cdecl` is used to define
462+
Swift functions that can be referenced from C.
463+
464+
Also similar to `@_silgen_name`, but a function declared with
465+
`@extern(c)` is assumed to use the C ABI, while `@_silgen_name`
466+
assumes the Swift ABI.
467+
452468
## `@_fixed_layout`
453469

454470
Same as `@frozen` but also works for classes.

include/swift/AST/Attr.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,8 @@ DECL_ATTR(_section, Section,
421421
DECL_ATTR(_rawLayout, RawLayout,
422422
OnStruct | UserInaccessible | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
423423
146)
424-
DECL_ATTR(_extern, Extern,
425-
OnFunc | ABIStableToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
424+
DECL_ATTR(extern, Extern,
425+
OnFunc | AllowMultipleAttributes | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
426426
147)
427427
SIMPLE_DECL_ATTR(_nonEscapable, NonEscapable,
428428
OnNominalType | UserInaccessible | ABIBreakingToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,

include/swift/AST/Attr.h

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ class DeclAttribute : public AttributeBase {
176176
kind : NumExposureKindBits
177177
);
178178

179+
SWIFT_INLINE_BITFIELD(ExternAttr, DeclAttribute, NumExternKindBits,
180+
kind : NumExternKindBits
181+
);
182+
179183
SWIFT_INLINE_BITFIELD(SynthesizedProtocolAttr, DeclAttribute, 1,
180184
isUnchecked : 1
181185
);
@@ -2335,22 +2339,48 @@ class ExposeAttr : public DeclAttribute {
23352339
}
23362340
};
23372341

2338-
/// Define the `@_extern` attribute, used to import external declarations in
2342+
/// Define the `@extern` attribute, used to import external declarations in
23392343
/// the specified way to interoperate with Swift.
23402344
class ExternAttr : public DeclAttribute {
2345+
SourceLoc LParenLoc, RParenLoc;
2346+
23412347
public:
2342-
ExternAttr(StringRef ModuleName, StringRef Name, SourceLoc AtLoc, SourceRange Range, bool Implicit)
2343-
: DeclAttribute(DAK_Extern, AtLoc, Range, Implicit),
2344-
ModuleName(ModuleName), Name(Name) {}
2348+
ExternAttr(llvm::Optional<StringRef> ModuleName,
2349+
llvm::Optional<StringRef> Name, SourceLoc AtLoc,
2350+
SourceLoc LParenLoc, SourceLoc RParenLoc, SourceRange Range,
2351+
ExternKind Kind, bool Implicit)
2352+
: DeclAttribute(DAK_Extern, AtLoc, Range, Implicit), LParenLoc(LParenLoc),
2353+
RParenLoc(RParenLoc), ModuleName(ModuleName), Name(Name) {
2354+
Bits.ExternAttr.kind = static_cast<unsigned>(Kind);
2355+
}
23452356

2346-
ExternAttr(StringRef ModuleName, StringRef Name, bool Implicit)
2347-
: ExternAttr(ModuleName, Name, SourceLoc(), SourceRange(), Implicit) {}
2357+
ExternAttr(llvm::Optional<StringRef> ModuleName,
2358+
llvm::Optional<StringRef> Name, ExternKind Kind, bool Implicit)
2359+
: ExternAttr(ModuleName, Name, SourceLoc(), SourceLoc(), SourceLoc(),
2360+
SourceRange(), Kind, Implicit) {}
23482361

23492362
/// The module name to import the named declaration in it
2350-
const StringRef ModuleName;
2363+
/// Used for Wasm import declaration.
2364+
const llvm::Optional<StringRef> ModuleName;
23512365

23522366
/// The declaration name to import
2353-
const StringRef Name;
2367+
/// std::nullopt if the declaration name is not specified with @extern(c)
2368+
const llvm::Optional<StringRef> Name;
2369+
2370+
SourceLoc getLParenLoc() const { return LParenLoc; }
2371+
SourceLoc getRParenLoc() const { return RParenLoc; }
2372+
2373+
/// Returns the kind of extern.
2374+
ExternKind getExternKind() const {
2375+
return static_cast<ExternKind>(Bits.ExternAttr.kind);
2376+
}
2377+
2378+
/// Returns the C name of the given declaration.
2379+
/// \p forDecl is the func decl that the attribute belongs to.
2380+
StringRef getCName(const FuncDecl *forDecl) const;
2381+
2382+
/// Find an ExternAttr with the given kind in the given DeclAttributes.
2383+
static ExternAttr *find(DeclAttributes &attrs, ExternKind kind);
23542384

23552385
static bool classof(const DeclAttribute *DA) {
23562386
return DA->getKind() == DAK_Extern;

include/swift/AST/AttrKind.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,24 @@ enum class ExposureKind: uint8_t {
112112
enum : unsigned { NumExposureKindBits =
113113
countBitsUsed(static_cast<unsigned>(ExposureKind::Last_ExposureKind)) };
114114

115+
/// This enum represents the possible values of the @extern attribute.
116+
enum class ExternKind: uint8_t {
117+
/// Reference an externally defined C function.
118+
/// The imported function has C function pointer representation,
119+
/// and is called using the C calling convention.
120+
C,
121+
/// Reference an externally defined function through WebAssembly's
122+
/// import mechanism.
123+
/// This does not specify the calling convention and can be used
124+
/// with other extern kinds together.
125+
/// Effectively, this is no-op on non-WebAssembly targets.
126+
Wasm,
127+
Last_ExternKind = Wasm
128+
};
129+
130+
enum : unsigned { NumExternKindBits =
131+
countBitsUsed(static_cast<unsigned>(ExternKind::Last_ExternKind)) };
132+
115133
enum DeclAttrKind : unsigned {
116134
#define DECL_ATTR(_, NAME, ...) DAK_##NAME,
117135
#include "swift/AST/Attr.def"

include/swift/AST/DiagnosticsParse.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1865,7 +1865,7 @@ ERROR(attr_rawlayout_expected_params,none,
18651865
"expected %1 argument after %0 argument in @_rawLayout attribute", (StringRef, StringRef))
18661866

18671867
ERROR(attr_extern_expected_label,none,
1868-
"expected %0 argument to @_extern attribute", (StringRef))
1868+
"expected %0 argument to @extern attribute", (StringRef))
18691869
//------------------------------------------------------------------------------
18701870
// MARK: Generics parsing diagnostics
18711871
//------------------------------------------------------------------------------

include/swift/AST/DiagnosticsSema.def

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,9 +1871,31 @@ ERROR(section_not_at_top_level,none,
18711871
ERROR(section_empty_name,none,
18721872
"@_section section name cannot be empty", ())
18731873

1874-
// @_extern
1874+
// @extern
1875+
ERROR(attr_extern_experimental,none,
1876+
"@extern requires '-enable-experimental-feature Extern'", ())
18751877
ERROR(extern_not_at_top_level_func,none,
1876-
"@_extern attribute can only be applied to global functions", ())
1878+
"@extern attribute can only be applied to global functions", ())
1879+
ERROR(extern_empty_c_name,none,
1880+
"expected non-empty C name in @extern attribute", ())
1881+
ERROR(extern_only_non_other_attr,none,
1882+
"@extern attribute cannot be applied to an '@%0' declaration", (StringRef))
1883+
WARNING(extern_c_maybe_invalid_name, none,
1884+
"C name '%0' may be invalid; explicitly specify the name in @extern(c) to suppress this warning",
1885+
(StringRef))
1886+
1887+
ERROR(c_func_variadic, none,
1888+
"cannot declare variadic argument %0 in %kind1",
1889+
(DeclName, const ValueDecl *))
1890+
ERROR(c_func_unsupported_specifier, none,
1891+
"cannot declare '%0' argument %1 in %kind2",
1892+
(StringRef, DeclName, const ValueDecl *))
1893+
ERROR(c_func_unsupported_type, none, "%0 cannot be represented in C",
1894+
(Type))
1895+
ERROR(c_func_async,none,
1896+
"async functions cannot be represented in C", ())
1897+
ERROR(c_func_throws,none,
1898+
"raising errors from C functions is not supported", ())
18771899

18781900
ERROR(expose_wasm_not_at_top_level_func,none,
18791901
"@_expose attribute with 'wasm' can only be applied to global functions", ())

include/swift/AST/TypeCheckRequests.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,26 @@ class IsObjCRequest :
205205
void cacheResult(bool value) const;
206206
};
207207

208+
/// Determine whether the given declaration has
209+
/// a C-compatible interface.
210+
class IsCCompatibleFuncDeclRequest :
211+
public SimpleRequest<IsCCompatibleFuncDeclRequest,
212+
bool(FuncDecl *),
213+
RequestFlags::Cached> {
214+
public:
215+
using SimpleRequest::SimpleRequest;
216+
217+
private:
218+
friend SimpleRequest;
219+
220+
// Evaluation.
221+
bool evaluate(Evaluator &evaluator, FuncDecl *decl) const;
222+
223+
public:
224+
// Caching.
225+
bool isCached() const { return true; }
226+
};
227+
208228
void simple_display(llvm::raw_ostream &out, CtorInitializerKind initKind);
209229

210230
/// Computes the kind of initializer for a given \c ConstructorDecl

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,3 +520,6 @@ SWIFT_REQUEST(TypeChecker, SerializeAttrGenericSignatureRequest,
520520
SWIFT_REQUEST(TypeChecker, IsFunctionBodySkippedRequest,
521521
bool(const AbstractFunctionDecl *),
522522
SeparatelyCached, NoLocationInfo)
523+
SWIFT_REQUEST(TypeChecker, IsCCompatibleFuncDeclRequest,
524+
bool(const FuncDecl *),
525+
Cached, NoLocationInfo)

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,9 @@ EXPERIMENTAL_FEATURE(StructLetDestructuring, true)
257257
/// lifetime-dependent results.
258258
EXPERIMENTAL_FEATURE(NonEscapableTypes, false)
259259

260+
/// Enable the `@extern` attribute.
261+
EXPERIMENTAL_FEATURE(Extern, true)
262+
260263
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
261264
#undef EXPERIMENTAL_FEATURE
262265
#undef UPCOMING_FEATURE

include/swift/Parse/Parser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,7 @@ class Parser {
10951095
ParserResult<DifferentiableAttr> parseDifferentiableAttribute(SourceLoc AtLoc,
10961096
SourceLoc Loc);
10971097

1098-
/// Parse the @_extern attribute.
1098+
/// Parse the @extern attribute.
10991099
bool parseExternAttribute(DeclAttributes &Attributes, bool &DiscardAttribute,
11001100
StringRef AttrName, SourceLoc AtLoc, SourceLoc Loc);
11011101

0 commit comments

Comments
 (0)