diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 9e21ad0bbd2ad..277d2d0c2f852 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -6071,9 +6071,7 @@ class AbstractStorageDecl : public ValueDecl { /// Return true if this is a property that either has storage /// or init accessor associated with it. - bool supportsInitialization() const { - return hasStorage() || hasInitAccessor(); - } + bool supportsInitialization() const; /// Return true if this storage has the basic accessors/capability /// to be mutated. This is generally constant after the accessors are diff --git a/include/swift/AST/DeclAttr.def b/include/swift/AST/DeclAttr.def index 3517bd718c87f..3441ad4e624db 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -774,7 +774,7 @@ DECL_ATTR(_rawLayout, RawLayout, 146) DECL_ATTR(_extern, Extern, - OnFunc, + OnFunc | OnVar, AllowMultipleAttributes | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr, 147) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index ccfbf026e22d2..ea3d8cffa2e79 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2123,8 +2123,8 @@ WARNING(reserved_runtime_symbol_name,none, // @_extern ERROR(attr_extern_experimental,none, "'@_extern' requires '-enable-experimental-feature Extern'", ()) -ERROR(extern_not_at_top_level_func,none, - "'@_extern' can only be applied to global functions", ()) +ERROR(extern_not_at_top_level,none, + "'@_extern' can only be applied to globals", ()) ERROR(extern_empty_c_name,none, "expected non-empty C name in '@_extern'", ()) ERROR(extern_only_non_other_attr,none, @@ -2134,6 +2134,8 @@ WARNING(extern_c_maybe_invalid_name, none, "C name '%0' may be invalid; explicitly specify the name in " "'@_extern(c)' to suppress this warning", (StringRef)) +ERROR(extern_variable_initializer, none, + "'@_extern' variable cannot have an initializer", ()) // @_staticExclusiveOnly ERROR(attr_static_exclusive_only_disabled,none, @@ -2170,13 +2172,14 @@ ERROR(c_func_variadic, none, ERROR(c_func_unsupported_specifier, none, "cannot declare '%0' argument %1 in %kind2", (StringRef, DeclName, const ValueDecl *)) -ERROR(c_func_unsupported_type, none, "%0 cannot be represented in C", +ERROR(c_unsupported_type, none, "%0 cannot be represented in C", (Type)) ERROR(c_func_async,none, "async functions cannot be represented in C", ()) ERROR(c_func_throws,none, "raising errors from C functions is not supported", ()) - +ERROR(c_var_computed,none, + "computed variable cannot be represented in C", ()) ERROR(expose_wasm_not_at_top_level_func,none, "'@_expose' with 'wasm' can only be applied to global " "functions", ()) diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 5b435ea1e3b6c..edae80feb0961 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -276,9 +276,9 @@ class IsObjCRequest : /// Determine whether the given declaration has /// a C-compatible interface. -class IsCCompatibleFuncDeclRequest : - public SimpleRequest { public: using SimpleRequest::SimpleRequest; @@ -287,7 +287,7 @@ class IsCCompatibleFuncDeclRequest : friend SimpleRequest; // Evaluation. - bool evaluate(Evaluator &evaluator, FuncDecl *decl) const; + bool evaluate(Evaluator &evaluator, ValueDecl *decl) const; public: // Caching. diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 500bf2145266a..9b5b76f262f0b 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -581,8 +581,8 @@ SWIFT_REQUEST(TypeChecker, SerializeAttrGenericSignatureRequest, SWIFT_REQUEST(TypeChecker, IsFunctionBodySkippedRequest, bool(const AbstractFunctionDecl *), SeparatelyCached, NoLocationInfo) -SWIFT_REQUEST(TypeChecker, IsCCompatibleFuncDeclRequest, - bool(const FuncDecl *), +SWIFT_REQUEST(TypeChecker, IsCCompatibleDeclRequest, + bool(const ValueDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, SemanticDeclAttrsRequest, DeclAttributes(const Decl *), diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 9ad2c3c8f61c4..166c7be7af4d3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -7977,6 +7977,13 @@ bool AbstractStorageDecl::hasInitAccessor() const { HasInitAccessorRequest{const_cast(this)}, false); } +bool AbstractStorageDecl::supportsInitialization() const { + if (getAttrs().hasAttribute()) + return false; + + return hasStorage() || hasInitAccessor(); +} + VarDecl::VarDecl(DeclKind kind, bool isStatic, VarDecl::Introducer introducer, SourceLoc nameLoc, Identifier name, DeclContext *dc, StorageIsMutable_t supportsMutation) @@ -8145,6 +8152,10 @@ bool VarDecl::isLazilyInitializedGlobal() const { if (getAttrs().hasAttribute()) return false; + // @_extern declarations are not initialized. + if (getAttrs().hasAttribute()) + return false; + // Top-level global variables in the main source file and in the REPL are not // lazily initialized. return !isTopLevelGlobal(); diff --git a/lib/ASTGen/Sources/ASTGen/Decls.swift b/lib/ASTGen/Sources/ASTGen/Decls.swift index 598bd4a05e39d..37fb0179fb0ce 100644 --- a/lib/ASTGen/Sources/ASTGen/Decls.swift +++ b/lib/ASTGen/Sources/ASTGen/Decls.swift @@ -612,7 +612,10 @@ extension ASTGenVisitor { } // @const/@section globals are not top-level, per SE-0492. - let isConst = attrs.attributes.hasAttribute(.Section) || attrs.attributes.hasAttribute(.ConstVal) + // We follow the same rule for @_extern. + let isConst = attrs.attributes.hasAttribute(.Section) + || attrs.attributes.hasAttribute(.ConstVal) + || attrs.attributes.hasAttribute(.Extern) let topLevelDecl: BridgedTopLevelCodeDecl? if self.declContext.isModuleScopeContext, self.declContext.parentSourceFile.isScriptMode, !isConst { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 2c001326b8283..863ea99a88484 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -8747,12 +8747,14 @@ Parser::parseDeclVar(ParseDeclOptions Flags, SourceLoc VarLoc = newBindingContext.getIntroducer() ? consumeToken() : Tok.getLoc(); bool IsConst = Attributes.hasAttribute() || - Attributes.hasAttribute(); + Attributes.hasAttribute() || + Attributes.hasAttribute(); // If this is a var in the top-level of script/repl source file, wrap the // PatternBindingDecl in a TopLevelCodeDecl, since it represents executable // code. The VarDecl and any accessor decls (for computed properties) go in // CurDeclContext. @const/@section globals are not top-level, per SE-0492. + // We follow the same rule for @_extern. TopLevelCodeDecl *topLevelDecl = nullptr; if (allowTopLevelCode() && CurDeclContext->isModuleScopeContext() && !IsConst) { diff --git a/lib/SILGen/SILGenGlobalVariable.cpp b/lib/SILGen/SILGenGlobalVariable.cpp index 3dcca948fdfc3..337a503bf3c7a 100644 --- a/lib/SILGen/SILGenGlobalVariable.cpp +++ b/lib/SILGen/SILGenGlobalVariable.cpp @@ -50,7 +50,8 @@ SILGlobalVariable *SILGenModule::getSILGlobalVariable(VarDecl *gDecl, formalLinkage = getDeclLinkage(gDecl); auto silLinkage = getSILLinkage(formalLinkage, forDef); - if (gDecl->getAttrs().hasAttribute()) { + auto cExternAttr = ExternAttr::find(gDecl->getAttrs(), ExternKind::C); + if (gDecl->getAttrs().hasAttribute() || cExternAttr) { silLinkage = SILLinkage::DefaultForDeclaration; if (! gDecl->hasInitialValue()) { forDef = NotForDefinition; @@ -77,6 +78,10 @@ SILGlobalVariable *SILGenModule::getSILGlobalVariable(VarDecl *gDecl, if (auto sectionAttr = gDecl->getAttrs().getAttribute()) silGlobal->setSection(sectionAttr->Name); + if (cExternAttr) { + silGlobal->setAsmName(cExternAttr->getCName(gDecl)); + } + return silGlobal; } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index aeb7098690963..29f0236f8bca5 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2538,58 +2538,78 @@ void AttributeChecker::visitExposeAttr(ExposeAttr *attr) { } } -bool IsCCompatibleFuncDeclRequest::evaluate(Evaluator &evaluator, - FuncDecl *FD) const { - if (FD->isInvalid()) +bool IsCCompatibleDeclRequest::evaluate(Evaluator &evaluator, + ValueDecl *VD) const { + if (VD->isInvalid()) return false; - bool foundError = false; - - if (FD->hasAsync()) { - FD->diagnose(diag::c_func_async); - foundError = true; - } - - if (FD->hasThrows()) { - FD->diagnose(diag::c_func_throws); - foundError = true; - } - - // --- Check for unsupported result types. - Type resultTy = FD->getResultInterfaceType(); - if (!resultTy->isVoid() && !resultTy->isRepresentableIn(ForeignLanguage::C, FD)) { - FD->diagnose(diag::c_func_unsupported_type, resultTy); - foundError = true; - } + if (auto FD = dyn_cast(VD)) { + bool foundError = false; - for (auto *param : *FD->getParameters()) { - // --- Check for unsupported specifiers. - if (param->isVariadic()) { - FD->diagnose(diag::c_func_variadic, param->getName(), FD); + if (FD->hasAsync()) { + FD->diagnose(diag::c_func_async); foundError = true; } - if (param->getSpecifier() != ParamSpecifier::Default) { - param - ->diagnose(diag::c_func_unsupported_specifier, - ParamDecl::getSpecifierSpelling(param->getSpecifier()), - param->getName(), FD) - .fixItRemove(param->getSpecifierLoc()); + + if (FD->hasThrows()) { + FD->diagnose(diag::c_func_throws); foundError = true; } - // --- Check for unsupported parameter types. - auto paramTy = param->getTypeInContext(); - if (!paramTy->isRepresentableIn(ForeignLanguage::C, FD)) { - param->diagnose(diag::c_func_unsupported_type, paramTy); + // --- Check for unsupported result types. + Type resultTy = FD->getResultInterfaceType(); + if (!resultTy->isVoid() && !resultTy->isRepresentableIn(ForeignLanguage::C, FD)) { + FD->diagnose(diag::c_unsupported_type, resultTy); foundError = true; } + + for (auto *param : *FD->getParameters()) { + // --- Check for unsupported specifiers. + if (param->isVariadic()) { + FD->diagnose(diag::c_func_variadic, param->getName(), FD); + foundError = true; + } + if (param->getSpecifier() != ParamSpecifier::Default) { + param + ->diagnose(diag::c_func_unsupported_specifier, + ParamDecl::getSpecifierSpelling(param->getSpecifier()), + param->getName(), FD) + .fixItRemove(param->getSpecifierLoc()); + foundError = true; + } + + // --- Check for unsupported parameter types. + auto paramTy = param->getTypeInContext(); + if (!paramTy->isRepresentableIn(ForeignLanguage::C, FD)) { + param->diagnose(diag::c_unsupported_type, paramTy); + foundError = true; + } + } + return !foundError; } - return !foundError; + + if (auto var = dyn_cast(VD)) { + Type varType = var->getInterfaceType(); + if (!varType->isRepresentableIn(ForeignLanguage::C, + var->getDeclContext())) { + var->diagnose(diag::c_unsupported_type, varType); + return true; + } + + if (!var->hasStorage()) { + var->diagnose(diag::c_var_computed); + return false; + } + + return true; + } + + return false; } -static bool isCCompatibleFuncDecl(FuncDecl *FD) { - return evaluateOrDefault(FD->getASTContext().evaluator, - IsCCompatibleFuncDeclRequest{FD}, {}); +static bool isCCompatibleDecl(ValueDecl *VD) { + return evaluateOrDefault(VD->getASTContext().evaluator, + IsCCompatibleDeclRequest{VD}, {}); } void AttributeChecker::visitExternAttr(ExternAttr *attr) { @@ -2598,17 +2618,27 @@ void AttributeChecker::visitExternAttr(ExternAttr *attr) { diagnoseAndRemoveAttr(attr, diag::attr_extern_experimental); return; } - - // Only top-level func or static func decls are currently supported. - auto *FD = dyn_cast(D); - if (!FD || (FD->getDeclContext()->isTypeContext() && !FD->isStatic())) { - diagnose(attr->getLocation(), diag::extern_not_at_top_level_func); - } + auto VD = dyn_cast(D); + if (!VD) + return; + + // Check the declaration context. + // FIXME: Unify this with @c / @_cdecl checking. + if (VD->getDeclContext()->isModuleScopeContext()) { + // Top-level declarations are okay. + } else if (VD->getDeclContext()->isTypeContext() && + !VD->getDeclContext()->getGenericSignatureOfContext() && + ((isa(VD) && cast(VD)->isStatic()) || + (isa(VD) && cast(VD)->isStatic()))) { + // Static members of non-generic types are okay. + } else { + diagnose(attr->getLocation(), diag::extern_not_at_top_level); + } // C name must not be empty. if (attr->getExternKind() == ExternKind::C) { - StringRef cName = attr->getCName(FD); + StringRef cName = attr->getCName(VD); if (cName.empty()) { diagnose(attr->getLocation(), diag::extern_empty_c_name); } else if (!attr->Name.has_value() && !clang::isValidAsciiIdentifier(cName)) { @@ -2630,10 +2660,10 @@ void AttributeChecker::visitExternAttr(ExternAttr *attr) { } // Ensure the decl has C compatible interface. Otherwise it produces diagnostics. - if (!isCCompatibleFuncDecl(FD)) { + if (!isCCompatibleDecl(VD)) { attr->setInvalid(); // Mark the decl itself invalid not to require body even with invalid ExternAttr. - FD->setInvalid(); + VD->setInvalid(); } } @@ -5697,7 +5727,9 @@ TypeChecker::diagnosticIfDeclCannotBeUnavailable(const Decl *D, static bool shouldBlockImplicitDynamic(Decl *D) { if (D->getAttrs().hasAttribute() || D->getAttrs().hasAttribute() || - D->getAttrs().hasAttribute()) + D->getAttrs().hasAttribute() || + D->getAttrs().hasAttribute() || + D->getAttrs().hasAttribute()) return true; return false; } diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 43b4c5754800a..df444e9ded490 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -2589,6 +2589,10 @@ class DeclChecker : public DeclVisitor { if (!var->hasStorage()) return; + // If the variable is @_extern, it never needs an initializer. + if (var->getAttrs().hasAttribute()) + return; + if (var->getAttrs().hasAttribute() || !ABIRoleInfo(var).providesAPI()) return; diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index af255d6792e30..cbe8911700c83 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -514,16 +514,22 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate( } } - auto isInitAccessorProperty = [](Pattern *pattern) { - auto *var = pattern->getSingleVar(); - return var && var->getAccessor(AccessorKind::Init); + auto supportsInitialization = [&] { + bool anySupportsInitialization = false; + pattern->forEachVariable([&](VarDecl *var) { + if (var->supportsInitialization()) { + anySupportsInitialization = true; + } + }); + + return anySupportsInitialization; }; // If we have a type but no initializer, check whether the type is // default-initializable. If so, do it. if (!pbe.isInitialized() && binding->isDefaultInitializable(entryNumber) && - (pattern->hasStorage() || isInitAccessorProperty(pattern))) { + supportsInitialization()) { if (auto defaultInit = TypeChecker::buildDefaultInitializer(patternType)) { // If we got a default initializer, install it and re-type-check it // to make sure it is properly coerced to the pattern type. @@ -598,7 +604,16 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate( Context.Diags.diagnose(binding->getPattern(entryNumber)->getLoc(), diag::destructuring_let_struct_stored_property_unsupported); } - + + // Extern declarations are not permitted to have initializers. + if (auto singleVar = binding->getSingleVar()) { + if (singleVar->getAttrs().hasAttribute() && + pbe.isInitialized()) { + singleVar->diagnose(diag::extern_variable_initializer) + .highlight(pbe.getOriginalInitRange()); + } + } + return &pbe; } diff --git a/test/IRGen/extern_c.swift b/test/IRGen/extern_c.swift index 0a0ee5ee2f6ef..8eee6eccb6038 100644 --- a/test/IRGen/extern_c.swift +++ b/test/IRGen/extern_c.swift @@ -2,6 +2,17 @@ // REQUIRES: swift_feature_Extern + +// CHECK: @pointer_c = external global +@_extern(c) +var pointer_c: UnsafeMutablePointer + +// CHECK: @nullable_pointer_c = external global +@_extern(c) +var nullable_pointer_c: UnsafeMutablePointer? + +func acceptInt(_: Int) { } + func test() { // CHECK: call void @explicit_extern_c() explicit_extern_c() @@ -12,6 +23,11 @@ func test() { default_arg_value() // CHECK: call void @default_arg_value(i32 24) default_arg_value(24) + + // CHECK: call void @swift_beginAccess(ptr @pointer_c + // CHECK-NEXT: [[POINTEE_VAL:%[0-9]+]] = load ptr, ptr @pointer_c + // CHECK-NEXT: call void @swift_endAccess + acceptInt(pointer_c.pointee) } test() diff --git a/test/attr/attr_extern.swift b/test/attr/attr_extern.swift index 9dd44298b137f..4ad31b43053ee 100644 --- a/test/attr/attr_extern.swift +++ b/test/attr/attr_extern.swift @@ -1,7 +1,5 @@ // RUN: %target-typecheck-verify-swift -enable-experimental-feature Extern -disable-availability-checking -// https://github.com/apple/swift/issues/70776 -// REQUIRES: github70776 // REQUIRES: swift_feature_Extern @_extern(wasm, module: "m1", name: "f1") @@ -13,7 +11,7 @@ func f2ErrorOnMissingNameLiteral(x: Int) -> Int // expected-error{{expected '{' @_extern(wasm, module: "m3", name) // expected-error {{expected ':' after label 'name'}} func f3ErrorOnMissingNameColon(x: Int) -> Int // expected-error{{expected '{' in body of function declaration}} -@_extern(wasm, module: "m4",) // expected-error {{expected name argument to @_extern attribute}} +@_extern(wasm, module: "m4",) // expected-error {{expected name argument to '@_extern'}} func f4ErrorOnMissingNameLabel(x: Int) -> Int // expected-error{{expected '{' in body of function declaration}} @_extern(wasm, module: "m5") // expected-error {{expected ',' in '_extern' attribute}} @@ -25,19 +23,19 @@ func f6ErrorOnMissingModuleLiteral(x: Int) -> Int // expected-error{{expected '{ @_extern(wasm, module) // expected-error {{expected ':' after label 'module'}} expected-error {{expected ',' in '_extern' attribute}} func f7ErrorOnMissingModuleColon(x: Int) -> Int // expected-error{{expected '{' in body of function declaration}} -@_extern(wasm,) // expected-error {{expected module argument to @_extern attribute}} expected-error {{expected ',' in '_extern' attribute}} +@_extern(wasm,) // expected-error {{expected module argument to '@_extern'}} expected-error {{expected ',' in '_extern' attribute}} func f8ErrorOnMissingModuleLabel(x: Int) -> Int // expected-error{{expected '{' in body of function declaration}} @_extern(wasm, module: "m9", name: "f9") func f9WithBody() {} // expected-error {{unexpected body of function declaration}} struct S { - @_extern(wasm, module: "m10", name: "f10") // expected-error {{@_extern attribute can only be applied to global functions}} + @_extern(wasm, module: "m10", name: "f10") // expected-error {{'@_extern' can only be applied to globals}} func f10Member() } func f11Scope() { - @_extern(wasm, module: "m11", name: "f11") + @_extern(wasm, module: "m11", name: "f11") // expected-error{{'@_extern' can only be applied to globals}} func f11Inner() } @@ -50,7 +48,7 @@ func externCValid() @_extern(c, "_start_with_underscore") func underscoredValid() -@_extern(c, "") // expected-error {{expected non-empty C name in @_extern attribute}} +@_extern(c, "") // expected-error {{expected non-empty C name in '@_extern'}} func emptyCName() // Allow specifying any identifier explicitly @@ -70,20 +68,28 @@ func omitCName() func editingCName() // expected-error {{expected '{' in body of function declaration}} struct StructScopeC { - @_extern(c, "member_decl") // expected-error {{@_extern attribute can only be applied to global functions}} + @_extern(c, "member_decl") // expected-error {{'@_extern' can only be applied to globals}} func memberDecl() @_extern(c, "static_member_decl") static func staticMemberDecl() + + @_extern(c, "global_static_variable") + static var globalVariable: Int +} + +struct GenericStruct { + @_extern(c, "static_member_decl") // expected-error{{'@_extern' can only be applied to globals}} + static func genericStaticMemberDecl() } func funcScopeC() { - @_extern(c, "func_scope_inner") + @_extern(c, "func_scope_inner") // expected-error {{'@_extern' can only be applied to globals}} func inner() } -@_extern(c, "c_value") // expected-error {{@_extern may only be used on 'func' declarations}} -var nonFunc: Int = 0 +@_extern(c, "c_value") +var nonFunc: Int = 0 // expected-error{{'@_extern' variable cannot have an initializer}} @_extern(c, "with_body") func withInvalidBody() {} // expected-error {{unexpected body of function declaration}} @@ -134,23 +140,23 @@ func throwsFuncC() throws // expected-error {{raising errors from C functions is @_extern(c) func genericFuncC(_: T) // expected-error {{'T' cannot be represented in C}} -@_extern(c) // expected-error {{@_extern attribute cannot be applied to an '@_cdecl' declaration}} +@_extern(c) // expected-error {{'@_extern' cannot be applied to an @_cdecl declaration}} @_cdecl("another_c_name") func withAtCDecl_C() -@_extern(wasm, module: "", name: "") // expected-error {{@_extern attribute cannot be applied to an '@_cdecl' declaration}} +@_extern(wasm, module: "", name: "") // expected-error {{'@_extern' cannot be applied to an @_cdecl declaration}} @_cdecl("another_c_name") func withAtCDecl_Wasm() -@_extern(c) // expected-error {{@_extern attribute cannot be applied to an '@_silgen_name' declaration}} +@_extern(c) // expected-error {{'@_extern' cannot be applied to an @_silgen_name declaration}} @_silgen_name("another_sil_name") func withAtSILGenName_C() -@_extern(wasm, module: "", name: "") // expected-error {{@_extern attribute cannot be applied to an '@_silgen_name' declaration}} +@_extern(wasm, module: "", name: "") // expected-error {{'@_extern' cannot be applied to an @_silgen_name declaration}} @_silgen_name("another_sil_name") func withAtSILGenName_Wasm() -@_extern(c) // expected-error {{@_extern attribute cannot be applied to an '@_silgen_name' declaration}} expected-error {{@_extern attribute cannot be applied to an '@_cdecl' declaration}} +@_extern(c) // expected-error {{'@_extern' cannot be applied to an @_silgen_name declaration}} expected-error {{'@_extern' cannot be applied to an @_cdecl declaration}} @_cdecl("another_c_name") @_silgen_name("another_sil_name") func withAtSILGenName_CDecl_C()