diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 6e8fdc6cbc8a6..946116e750dc2 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -21,6 +21,7 @@ #include "swift/AST/AttrKind.h" #include "swift/AST/DiagnosticKind.h" #include "swift/AST/DiagnosticList.h" +#include "swift/AST/ExportKind.h" #include "swift/AST/GenericTypeParamKind.h" #include "swift/AST/Identifier.h" #include "swift/AST/LayoutConstraintKind.h" @@ -956,6 +957,12 @@ BridgedImplementsAttr BridgedImplementsAttr_createParsed( swift::SourceRange range, BridgedTypeRepr cProtocolType, BridgedDeclNameRef cMemberName, BridgedDeclNameLoc cMemberNameLoc); +SWIFT_NAME("BridgedExportAttr.createParsed(_:atLoc:range:kind:)") +BridgedExportAttr BridgedExportAttr_createParsed(BridgedASTContext cContext, + swift::SourceLoc atLoc, + swift::SourceRange range, + swift::ExportKind kind); + SWIFT_NAME("BridgedInlineAttr.createParsed(_:atLoc:range:kind:)") BridgedInlineAttr BridgedInlineAttr_createParsed(BridgedASTContext cContext, swift::SourceLoc atLoc, diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index b9851c6ddca39..a0dd7f7b72bfb 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -23,6 +23,7 @@ #include "swift/AST/AvailabilityRange.h" #include "swift/AST/ConcreteDeclRef.h" #include "swift/AST/DeclNameLoc.h" +#include "swift/AST/ExportKind.h" #include "swift/AST/Identifier.h" #include "swift/AST/KnownProtocols.h" #include "swift/AST/LifetimeDependence.h" @@ -2955,6 +2956,35 @@ enum class NonSendableKind : uint8_t { Assumed }; +/// Specify whether the declaration should be exported as an interface or +/// an implementation. +class ExportAttr : public DeclAttribute { +public: + /// How this declaration is exported. + const ExportKind exportKind; + + ExportAttr(SourceLoc atLoc, SourceRange range, ExportKind exportKind, + bool implicit = false) + : DeclAttribute(DeclAttrKind::Export, atLoc, range, implicit), + exportKind(exportKind) {} + + ExportAttr(ExportKind exportKind, bool implicit = false) + : ExportAttr(SourceLoc(), SourceRange(), exportKind, implicit) { } + + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DeclAttrKind::Export; + } + + /// Create a copy of this attribute. + ExportAttr *clone(ASTContext &ctx) const { + return new (ctx) ExportAttr(AtLoc, Range, exportKind, isImplicit()); + } + + bool isEquivalent(const ExportAttr *other, Decl *attachedTo) const { + return exportKind == other->exportKind; + } +}; + /// Marks a declaration as explicitly non-Sendable. class NonSendableAttr : public DeclAttribute { public: diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index c3af583ff108c..9c97b6b2b0ebb 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -1085,12 +1085,22 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated, public Swi /// behaviors for it and, if it's an extension, its members. bool isObjCImplementation() const; + /// True if this declaration should always have its implementation made + /// available to the client, and not have an ABI symbol. + /// + /// This can be spelled with @export(implementation) or the historical + /// @_alwaysEmitIntoClient. + bool isAlwaysEmittedIntoClient() const; + /// True if this declaration should never have its implementation made /// available to any client. This overrides cross-module optimization and /// optimizations that might use the implementation, such that the only /// implementation of this function is the one compiled into its owning /// module. Practically speaking, this prohibits serialization of the SIL /// for this definition. + /// + /// This can be spelled with @export(interface) or the historical + /// @_neverEmitIntoClient. bool isNeverEmittedIntoClient() const; using AuxiliaryDeclCallback = llvm::function_ref; diff --git a/include/swift/AST/DeclAttr.def b/include/swift/AST/DeclAttr.def index 5140bf0117a10..c2c3ddbba0101 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -558,7 +558,10 @@ SIMPLE_DECL_ATTR(noDerivative, NoDerivative, ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | ForbiddenInABIAttr, 100) -// Unused '101' +DECL_ATTR(export, Export, + OnVar | OnSubscript | OnAbstractFunction, + ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr, + 101) CONTEXTUAL_SIMPLE_DECL_ATTR(actor, Actor, OnClass, diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index d032ebfc37df6..cb391f66cc839 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4170,6 +4170,10 @@ ERROR(final_not_allowed_here,none, "'final' may only be applied to classes, properties, methods, and " "subscripts", ()) +ERROR(attr_incompatible_with_attr,none, + "'%0' cannot be used with '%1'", + (DeclAttribute, DeclAttribute)) + ERROR(attr_incompatible_with_non_final,none, "'%0' cannot be applied to a non-final %kindonly1", (DeclAttribute, const ValueDecl *)) @@ -5369,7 +5373,7 @@ GROUPED_ERROR(opaque_type_unsupported_availability,OpaqueTypeInference,none, "a default argument value|" \ "a property initializer in a '@frozen' type|" \ "a '@backDeployed' function|" \ - "an embedded function not marked '@_neverEmitIntoClient'}" + "an embedded function not marked '@export(interface)'}" ERROR(discard_wrong_context_decl,none, "'discard' statement cannot appear in %kindonly0", diff --git a/include/swift/AST/ExportKind.h b/include/swift/AST/ExportKind.h new file mode 100644 index 0000000000000..d870703e042aa --- /dev/null +++ b/include/swift/AST/ExportKind.h @@ -0,0 +1,37 @@ +//===-- AST/ExportKind.h ----------------------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_EXPORT_KIND_H +#define SWIFT_AST_EXPORT_KIND_H + +/// `ExportKind.h` is imported into Swift. Be *very* careful with what you +/// include here and keep these includes minimal! +/// +/// See include guidelines and caveats in `BasicBridging.h`. +#include "swift/Basic/SwiftBridging.h" + +namespace swift { + +/// How a particular declaration is exported per the @export attribute. +enum class ENUM_EXTENSIBILITY_ATTR(closed) ExportKind { + /// Export only the interface to this declaration (e.g., as a callable symbol) + /// and never it's definition. + Interface SWIFT_NAME("interface"), + + /// Export only the implementation of this declaration and do not produce a + /// symbol. + Implementation SWIFT_NAME("implementation"), +}; + +} // namespace swift + +#endif // SWIFT_AST_EXPORT_KIND_H diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index 02ef359f568e3..351451ccd1323 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -332,6 +332,8 @@ IDENTIFIER(always) IDENTIFIER_(_always) IDENTIFIER_(assumed) IDENTIFIER(checked) +IDENTIFIER(interface) +IDENTIFIER(implementation) IDENTIFIER(never) IDENTIFIER(none) IDENTIFIER(safe) diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index 980cf767bac8a..6c544f6db17bc 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -1421,7 +1421,7 @@ class SILFunction return false; auto *V = getLocation().getAsASTNode(); - return V && V->getAttrs().hasAttribute(); + return V && V->isAlwaysEmittedIntoClient(); } /// Return whether this function has attribute @used on it diff --git a/lib/APIDigester/ModuleAnalyzerNodes.cpp b/lib/APIDigester/ModuleAnalyzerNodes.cpp index fe1699330f754..58d8ccacbfecf 100644 --- a/lib/APIDigester/ModuleAnalyzerNodes.cpp +++ b/lib/APIDigester/ModuleAnalyzerNodes.cpp @@ -1764,7 +1764,7 @@ SDKContext::shouldIgnore(Decl *D, const Decl* Parent) const { // Exclude decls with @_alwaysEmitIntoClient if we are checking ABI. // These decls are considered effectively public because they are usable // from inline, so we have to manually exclude them here. - if (D->getAttrs().hasAttribute()) + if (D->isAlwaysEmittedIntoClient()) return true; } else { if (D->isPrivateSystemDecl(false)) diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index d121ffc015674..104ddd8a3a896 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -590,6 +590,15 @@ static StringRef getDumpString(InlineKind kind) { } llvm_unreachable("unhandled InlineKind"); } +static StringRef getDumpString(ExportKind kind) { + switch (kind) { + case ExportKind::Interface: + return "interface"; + case ExportKind::Implementation: + return "implementation"; + } + llvm_unreachable("unhandled ExportKind"); +} static StringRef getDumpString(MacroRole role) { return getMacroRoleString(role); } @@ -5306,6 +5315,11 @@ class PrintAttribute : public AttributeVisitor, printField(Attr->getKind(), Label::always("kind")); printFoot(); } + void visitExportAttr(ExportAttr *Attr, Label label) { + printCommon(Attr, "export_attr", label); + printField(Attr->exportKind, Label::always("kind")); + printFoot(); + } void visitLifetimeAttr(LifetimeAttr *Attr, Label label) { printCommon(Attr, "lifetime_attr", label); // FIXME: Improve, more detailed info. diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index bde72ed632bf0..e69a747982491 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -1129,6 +1129,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, case DeclAttrKind::AccessControl: case DeclAttrKind::ReferenceOwnership: case DeclAttrKind::Effects: + case DeclAttrKind::Export: case DeclAttrKind::Optimize: case DeclAttrKind::Exclusivity: case DeclAttrKind::NonSendable: @@ -1932,6 +1933,15 @@ StringRef DeclAttribute::getAttrName() const { case EffectsKind::Custom: return "_effects"; } + case DeclAttrKind::Export: { + switch (cast(this)->exportKind) { + case ExportKind::Interface: + return "export(interface)"; + case ExportKind::Implementation: + return "export(implementation)"; + } + llvm_unreachable("Invalid export kind"); + } case DeclAttrKind::AccessControl: case DeclAttrKind::SetterAccess: { AccessLevel access = cast(this)->getAccess(); diff --git a/lib/AST/Bridging/DeclAttributeBridging.cpp b/lib/AST/Bridging/DeclAttributeBridging.cpp index 3af8c1e5a8327..a99e0cef92d4f 100644 --- a/lib/AST/Bridging/DeclAttributeBridging.cpp +++ b/lib/AST/Bridging/DeclAttributeBridging.cpp @@ -351,6 +351,14 @@ BridgedImplementsAttr BridgedImplementsAttr_createParsed( cMemberName.unbridged().getFullName(), cMemberNameLoc.unbridged()); } +BridgedExportAttr BridgedExportAttr_createParsed(BridgedASTContext cContext, + SourceLoc atLoc, + SourceRange range, + swift::ExportKind kind) { + return new (cContext.unbridged()) ExportAttr(atLoc, range, kind); +} + + BridgedInlineAttr BridgedInlineAttr_createParsed(BridgedASTContext cContext, SourceLoc atLoc, SourceRange range, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index b741e884aa3b6..f5076270ba96c 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2276,8 +2276,32 @@ bool Decl::isObjCImplementation() const { return getAttrs().hasAttribute(/*AllowInvalid=*/true); } +bool Decl::isAlwaysEmittedIntoClient() const { + // @export(implementation) + if (auto exportAttr = getAttrs().getAttribute()) { + if (exportAttr->exportKind == ExportKind::Implementation) + return true; + } + + // @_alwaysEmitIntoClient + if (getAttrs().hasAttribute()) + return true; + + return false; +} + bool Decl::isNeverEmittedIntoClient() const { - return getAttrs().hasAttribute(); + // @export(interface) + if (auto exportAttr = getAttrs().getAttribute()) { + if (exportAttr->exportKind == ExportKind::Interface) + return true; + } + + // @_neverEmitIntoClient + if (getAttrs().hasAttribute()) + return true; + + return false; } PatternBindingDecl::PatternBindingDecl(SourceLoc StaticLoc, @@ -4962,14 +4986,14 @@ bool ValueDecl::isUsableFromInline() const { return abiRole.getCounterpart()->isUsableFromInline(); if (getAttrs().hasAttribute() || - getAttrs().hasAttribute() || + isAlwaysEmittedIntoClient() || hasAttributeWithInlinableSemantics()) return true; if (auto *accessor = dyn_cast(this)) { auto *storage = accessor->getStorage(); if (storage->getAttrs().hasAttribute() || - storage->getAttrs().hasAttribute() || + storage->isAlwaysEmittedIntoClient() || storage->hasAttributeWithInlinableSemantics()) return true; } @@ -4977,7 +5001,7 @@ bool ValueDecl::isUsableFromInline() const { if (auto *opaqueType = dyn_cast(this)) { if (auto *namingDecl = opaqueType->getNamingDecl()) { if (namingDecl->getAttrs().hasAttribute() || - namingDecl->getAttrs().hasAttribute() || + namingDecl->isAlwaysEmittedIntoClient() || namingDecl->hasAttributeWithInlinableSemantics()) return true; } diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 56dbbe4cf5678..7975c29ba3d50 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -593,7 +593,7 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator, return {FragileFunctionKind::Inlinable}; } - if (AFD->getAttrs().hasAttribute()) { + if (AFD->isAlwaysEmittedIntoClient()) { return {FragileFunctionKind::AlwaysEmitIntoClient}; } @@ -608,7 +608,7 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator, if (storage->hasAttributeWithInlinableSemantics()) { return {FragileFunctionKind::Inlinable}; } - if (storage->getAttrs().hasAttribute()) { + if (storage->isAlwaysEmittedIntoClient()) { return {FragileFunctionKind::AlwaysEmitIntoClient}; } if (storage->isBackDeployed()) { diff --git a/lib/AST/SwiftNameTranslation.cpp b/lib/AST/SwiftNameTranslation.cpp index ed9975acb0339..4e023d5cb9138 100644 --- a/lib/AST/SwiftNameTranslation.cpp +++ b/lib/AST/SwiftNameTranslation.cpp @@ -301,9 +301,8 @@ swift::cxx_translation::getDeclRepresentation( if (isa(VD)) return {Unsupported, UnrepresentableMacro}; GenericSignature genericSignature; - // Don't expose @_alwaysEmitIntoClient decls as they require their - // bodies to be emitted into client. - if (VD->getAttrs().hasAttribute()) + // Don't expose decls with definitions that are emitted into the client. + if (VD->isAlwaysEmittedIntoClient()) return {Unsupported, UnrepresentableRequiresClientEmission}; if (auto *AFD = dyn_cast(VD)) { if (AFD->hasAsync()) diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index 5e66153edcd3e..171db1ef6dd04 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -150,6 +150,8 @@ extension ASTGenVisitor { return handle(self.generateEffectsAttr(attribute: node)?.asDeclAttribute) case .Exclusivity: return handle(self.generateExclusivityAttr(attribute: node)?.asDeclAttribute) + case .Export: + return handle(self.generateExportAttr(attribute: node)?.asDeclAttribute) case .Expose: return handle(self.generateExposeAttr(attribute: node)?.asDeclAttribute) case .Extern: @@ -1071,6 +1073,33 @@ extension ASTGenVisitor { ) } + /// E.g.: + /// ``` + /// @export(interface) + /// @export(implementation) + /// ``` + func generateExportAttr(attribute node: AttributeSyntax) -> BridgedExportAttr? { + let kind: swift.ExportKind? = self.generateSingleAttrOption( + attribute: node, + { + switch $0.rawText { + case "interface": return .interface + case "implementation": return .implementation + default: return nil + } + } + ) + guard let kind else { + return nil + } + return .createParsed( + self.ctx, + atLoc: self.generateSourceLoc(node.atSign), + range: self.generateAttrSourceRange(node), + kind: kind + ) + } + /// E.g.: /// ``` /// @inline(never) diff --git a/lib/ClangImporter/SwiftDeclSynthesizer.cpp b/lib/ClangImporter/SwiftDeclSynthesizer.cpp index b7c95dc53c99d..1fe17c97de279 100644 --- a/lib/ClangImporter/SwiftDeclSynthesizer.cpp +++ b/lib/ClangImporter/SwiftDeclSynthesizer.cpp @@ -2632,8 +2632,8 @@ SwiftDeclSynthesizer::makeDefaultArgument(const clang::ParmVarDecl *param, ImporterImpl.ImportedHeaderUnit); funcDecl->setBodySynthesizer(synthesizeDefaultArgumentBody, (void *)param); funcDecl->setAccess(AccessLevel::Public); - funcDecl->addAttribute(new (ctx) - AlwaysEmitIntoClientAttr(/*IsImplicit=*/true)); + funcDecl->addAttribute( + new (ctx) ExportAttr(ExportKind::Implementation, /*IsImplicit=*/true)); // At this point, the parameter/return types of funcDecl might not be imported // into Swift completely, meaning that their protocol conformances might not // be populated yet. Prevent LifetimeDependenceInfoRequest from prematurely @@ -3184,8 +3184,8 @@ FuncDecl *SwiftDeclSynthesizer::makeAvailabilityDomainPredicate( funcDecl->setBodySynthesizer(synthesizeAvailabilityDomainPredicateBody, (void *)var); funcDecl->setAccess(AccessLevel::Public); - funcDecl->addAttribute(new (ctx) - AlwaysEmitIntoClientAttr(/*IsImplicit=*/true)); + funcDecl->addAttribute( + new (ctx) ExportAttr(ExportKind::Implementation, /*IsImplicit=*/true)); ImporterImpl.availabilityDomainPredicates[var] = funcDecl; diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp index c28a81412c106..249709a8da563 100644 --- a/lib/IRGen/Linking.cpp +++ b/lib/IRGen/Linking.cpp @@ -815,14 +815,14 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const { // With conditionally available substitutions, the opaque result type // descriptor has to be emitted into a client module when associated with - // `@_alwaysEmitIntoClient` declaration which means it's linkage + // always-emitted-into-client declaration which means it's linkage // has to be "shared". // // If we don't have conditionally available substitutions, we won't emit // the descriptor at all, but still make sure we report "shared" linkage // so that TBD files don't include a bogus symbol. auto *srcDecl = opaqueType->getNamingDecl(); - if (srcDecl->getAttrs().hasAttribute()) + if (srcDecl->isAlwaysEmittedIntoClient()) return SILLinkage::Shared; return getSILLinkage(getDeclLinkage(opaqueType), forDefinition); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 863ea99a88484..4fca1635fe94c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2788,6 +2788,21 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes, break; } + case DeclAttrKind::Export: { + auto kind = parseSingleAttrOption( + *this, Loc, AttrRange, AttrName, DK, { + { Context.Id_interface, ExportKind::Interface }, + { Context.Id_implementation, ExportKind::Implementation }, + }); + if (!kind) + return makeParserSuccess(); + + if (!DiscardAttribute) + Attributes.add(new (Context) ExportAttr(AtLoc, AttrRange, *kind)); + + break; + } + case DeclAttrKind::Inline: { auto kind = parseSingleAttrOption( *this, Loc, AttrRange, AttrName, DK, { diff --git a/lib/SIL/IR/SILDeclRef.cpp b/lib/SIL/IR/SILDeclRef.cpp index f09fd457fe5a4..9e8a1a69e18ce 100644 --- a/lib/SIL/IR/SILDeclRef.cpp +++ b/lib/SIL/IR/SILDeclRef.cpp @@ -505,14 +505,14 @@ static LinkageLimit getLinkageLimit(SILDeclRef constant) { case Kind::Deallocator: case Kind::IsolatedDeallocator: case Kind::Destroyer: { - // @_alwaysEmitIntoClient declarations are like the default arguments of + // Always-emit-into-client declarations are like the default arguments of // public functions; they are roots for dead code elimination and have // serialized bodies, but no public symbol in the generated binary. - if (d->getAttrs().hasAttribute()) + if (d->isAlwaysEmittedIntoClient()) return Limit::AlwaysEmitIntoClient; if (auto accessor = dyn_cast(d)) { auto *storage = accessor->getStorage(); - if (storage->getAttrs().hasAttribute()) + if (storage->isAlwaysEmittedIntoClient()) return Limit::AlwaysEmitIntoClient; } break; @@ -1192,13 +1192,13 @@ bool SILDeclRef::declHasNonUniqueDefinition(const ValueDecl *decl) { if (!decl->getASTContext().LangOpts.hasFeature(Feature::Embedded)) return false; - // If the declaration is marked as @_neverEmitIntoClient, it has a unique - // definition. + // If the declaration is marked as never being emitted into the client, it + // has a unique definition. if (decl->isNeverEmittedIntoClient()) return false; - /// @_alwaysEmitIntoClient means that we have a non-unique definition. - if (decl->getAttrs().hasAttribute()) + /// Always-emit-into-client means that we have a non-unique definition. + if (decl->isAlwaysEmittedIntoClient()) return true; // If the declaration is marked in a manner that indicates that other diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 758d5aa541f99..937e456853a85 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -4734,7 +4734,7 @@ KeyPathPatternComponent SILGenModule::emitKeyPathComponentForDecl( // descriptor that may not exist in older versions of their home dylib. // Their definition is also always entirely visible to clients so it isn't // needed. - if (baseDecl->getAttrs().hasAttribute()) { + if (baseDecl->isAlwaysEmittedIntoClient()) { return false; } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index a3379c8a0d0da..8c4e90aa68357 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -161,7 +161,6 @@ class AttributeChecker : public AttributeVisitor { #define IGNORED_ATTR(X) void visit##X##Attr(X##Attr *) {} IGNORED_ATTR(AlwaysEmitIntoClient) - IGNORED_ATTR(NeverEmitIntoClient) IGNORED_ATTR(HasInitialValue) IGNORED_ATTR(ClangImporterSynthesizedType) IGNORED_ATTR(Convenience) @@ -408,6 +407,8 @@ class AttributeChecker : public AttributeVisitor { void visitInlineAttr(InlineAttr *attr); void visitOptimizeAttr(OptimizeAttr *attr); void visitExclusivityAttr(ExclusivityAttr *attr); + void visitNeverEmitIntoClientAttr(NeverEmitIntoClientAttr *attr); + void visitExportAttr(ExportAttr *attr); void visitDiscardableResultAttr(DiscardableResultAttr *attr); void visitDynamicReplacementAttr(DynamicReplacementAttr *attr); @@ -3836,6 +3837,27 @@ void AttributeChecker::visitExclusivityAttr(ExclusivityAttr *attr) { attr->setInvalid(); } +void AttributeChecker::visitExportAttr(ExportAttr *attr) { + // @export cannot be combined with any of @inlinable, @usableFromInline, + // @_alwaysEmitIntoClient, or @_neverEmitIntoClient + if (auto other = D->getAttrs().getAttribute()) + diagnoseAndRemoveAttr(attr, diag::attr_incompatible_with_attr, attr, other); + if (auto other = D->getAttrs().getAttribute()) + diagnoseAndRemoveAttr(attr, diag::attr_incompatible_with_attr, attr, other); + if (auto other = D->getAttrs().getAttribute()) + diagnoseAndRemoveAttr(attr, diag::attr_incompatible_with_attr, attr, other); + if (auto other = D->getAttrs().getAttribute()) + diagnoseAndRemoveAttr(attr, diag::attr_incompatible_with_attr, attr, other); + if (auto other = D->getAttrs().getAttribute()) + diagnoseAndRemoveAttr(attr, diag::attr_incompatible_with_attr, attr, other); +} + +void AttributeChecker::visitNeverEmitIntoClientAttr(NeverEmitIntoClientAttr *attr) { + Ctx.Diags.diagnose(attr->getStartLoc(), diag::attr_renamed_warning, + "_neverEmitIntoClient", "export(interface)") + .fixItReplace(attr->getRangeWithAt(), "@export(interface)"); +} + void AttributeChecker::visitDiscardableResultAttr(DiscardableResultAttr *attr) { if (auto *FD = dyn_cast(D)) { if (auto result = FD->getResultInterfaceType()) { @@ -5345,6 +5367,11 @@ void AttributeChecker::checkBackDeployedAttrs( AEICA, D); } + if (auto *EA = D->getAttrs().getAttribute()) { + diagnoseAndRemoveAttr(EA, diag::attr_incompatible_with_back_deployed, + EA, D); + } + if (auto *TA = D->getAttrs().getAttribute()) { diagnoseAndRemoveAttr(TA, diag::attr_incompatible_with_back_deployed, TA, D); @@ -7265,8 +7292,8 @@ static bool typeCheckDerivativeAttr(DerivativeAttr *attr) { return true; } - if (originalAFD->getAttrs().hasAttribute() != - derivative->getAttrs().hasAttribute()) { + if (originalAFD->isAlwaysEmittedIntoClient() != + derivative->isAlwaysEmittedIntoClient()) { diags.diagnose(derivative->getLoc(), diag::derivative_attr_always_emit_into_client_mismatch); return true; diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index 2d05f845a75ab..87067348c93e5 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -3655,9 +3655,7 @@ static bool declNeedsExplicitAvailability(const Decl *decl) { } // Skip functions emitted into clients, SPI or implicit. - if (decl->getAttrs().hasAttribute() || - decl->isSPI() || - decl->isImplicit()) + if (decl->isAlwaysEmittedIntoClient() || decl->isSPI() || decl->isImplicit()) return false; // Skip unavailable decls. diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 5861b1b0dfbfa..67a0f41076b7a 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1600,6 +1600,7 @@ namespace { UNINTERESTING_ATTR(DynamicCallable) UNINTERESTING_ATTR(DynamicMemberLookup) UNINTERESTING_ATTR(SILGenName) + UNINTERESTING_ATTR(Export) UNINTERESTING_ATTR(Exported) UNINTERESTING_ATTR(ForbidSerializingReference) UNINTERESTING_ATTR(GKInspectable) diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index a0ceef1c73f36..e53afd46ff06f 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -6177,6 +6177,14 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() { break; } + case decls_block::Export_DECL_ATTR: { + unsigned kind; + serialization::decls_block::ExportDeclAttrLayout::readRecord( + scratch, kind); + Attr = new (ctx) ExportAttr((ExportKind)kind); + break; + } + case decls_block::NonSendable_DECL_ATTR: { unsigned kind; serialization::decls_block::NonSendableDeclAttrLayout::readRecord( diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 2e10089b6b0c3..e760f97b348a9 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// 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. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 972; // SIL asmname string table +const uint16_t SWIFTMODULE_VERSION_MINOR = 973; // @export attribute /// A standard hash seed used for all string hashes in a serialized module. /// @@ -2412,6 +2412,11 @@ namespace decls_block { BCFixed<2> // inline value >; + using ExportDeclAttrLayout = BCRecordLayout< + Export_DECL_ATTR, + BCFixed<1> // export kind value + >; + using NonSendableDeclAttrLayout = BCRecordLayout< NonSendable_DECL_ATTR, BCFixed<1> // non-sendable kind diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index d520e7602e6a4..e1ad26109b956 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3070,6 +3070,14 @@ class Serializer::DeclSerializer : public DeclVisitor { return; } + case DeclAttrKind::Export: { + auto *theAttr = cast(DA); + auto abbrCode = S.DeclTypeAbbrCodes[ExportDeclAttrLayout::Code]; + ExportDeclAttrLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, + (unsigned)theAttr->exportKind); + return; + } + case DeclAttrKind::NonSendable: { auto *theAttr = cast(DA); auto abbrCode = S.DeclTypeAbbrCodes[NonSendableDeclAttrLayout::Code]; diff --git a/test/IDE/complete_decl_attribute.swift b/test/IDE/complete_decl_attribute.swift index 9e020bf773abd..c9653b660cc4e 100644 --- a/test/IDE/complete_decl_attribute.swift +++ b/test/IDE/complete_decl_attribute.swift @@ -118,6 +118,7 @@ actor MyGenericGlobalActor { // KEYWORD2-NEXT: Keyword/None: derivative[#Func Attribute#]; name=derivative // KEYWORD2-NEXT: Keyword/None: transpose[#Func Attribute#]; name=transpose // KEYWORD2-NEXT: Keyword/None: noDerivative[#Func Attribute#]; name=noDerivative +// KEYWORD2-NEXT: Keyword/None: export[#Func Attribute#]; name=export // KEYWORD2-NEXT: Keyword/None: Sendable[#Func Attribute#]; name=Sendable // KEYWORD2-NEXT: Keyword/None: preconcurrency[#Func Attribute#]; name=preconcurrency // KEYWORD2-NEXT: Keyword/None: backDeployed[#Func Attribute#]; name=backDeployed diff --git a/test/IRGen/alwaysEmitIntoClient.swift b/test/IRGen/alwaysEmitIntoClient.swift deleted file mode 100644 index da6a10cd550fb..0000000000000 --- a/test/IRGen/alwaysEmitIntoClient.swift +++ /dev/null @@ -1,32 +0,0 @@ -// RUN: %target-swift-frontend -emit-ir %s -O | %FileCheck %s --check-prefix=OPTIMIZED -// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s -// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s --check-prefix=NEGATIVE -// RUN: %target-swift-frontend -emit-ir -primary-file %s | %FileCheck %s --check-prefix=PRIMARY - -// Make sure that @_alwaysEmitIntoClient functions are lazily -// emitted in WMO builds. - -// Both functions are eliminated in optimized builds; the first is inlined -// into the caller, and the second is eliminated since it was never called. - -// OPTIMIZED-NOT: define weak_odr hidden swiftcc void @"$s20alwaysEmitIntoClient18referencedFunctionyyF"() {{.*}} { -// OPTIMIZED-NOT: define weak_odr hidden swiftcc void @"$s20alwaysEmitIntoClient20unreferencedFunctionyyF"() {{.*}} { - -// The unreferenced function should be eliminated in an unoptimized WMO -// build too, since it was never referenced from inside the module. - -// CHECK-LABEL: define linkonce_odr hidden swiftcc void @"$s20alwaysEmitIntoClient18referencedFunctionyyF"() {{.*}} { -// NEGATIVE-NOT: define linkonce_odr hidden swiftcc void @"$s20alwaysEmitIntoClient20unreferencedFunctionyyF"() {{.*}} { - -// In non-WMO mode, both functions must be emitted since they could be -// referenced from other translation units. - -// PRIMARY-LABEL: define weak_odr hidden swiftcc void @"$s20alwaysEmitIntoClient18referencedFunctionyyF"() {{.*}} { -// PRIMARY-LABEL: define weak_odr hidden swiftcc void @"$s20alwaysEmitIntoClient20unreferencedFunctionyyF"() {{.*}} { - -@_alwaysEmitIntoClient public func referencedFunction() {} -@_alwaysEmitIntoClient public func unreferencedFunction() {} - -public func referencesFunction() { - referencedFunction() -} diff --git a/test/IRGen/exportImplementation.swift b/test/IRGen/exportImplementation.swift new file mode 100644 index 0000000000000..f5a29b56508a7 --- /dev/null +++ b/test/IRGen/exportImplementation.swift @@ -0,0 +1,32 @@ +// RUN: %target-swift-frontend -emit-ir %s -O | %FileCheck %s --check-prefix=OPTIMIZED +// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s +// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s --check-prefix=NEGATIVE +// RUN: %target-swift-frontend -emit-ir -primary-file %s | %FileCheck %s --check-prefix=PRIMARY + +// Make sure that @export(implementation) functions are lazily +// emitted in WMO builds. + +// Both functions are eliminated in optimized builds; the first is inlined +// into the caller, and the second is eliminated since it was never called. + +// OPTIMIZED-NOT: define weak_odr hidden swiftcc void @"$s20exportImplementation18referencedFunctionyyF"() {{.*}} { +// OPTIMIZED-NOT: define weak_odr hidden swiftcc void @"$s20exportImplementation20unreferencedFunctionyyF"() {{.*}} { + +// The unreferenced function should be eliminated in an unoptimized WMO +// build too, since it was never referenced from inside the module. + +// CHECK-LABEL: define linkonce_odr hidden swiftcc void @"$s20exportImplementation18referencedFunctionyyF"() {{.*}} { +// NEGATIVE-NOT: define linkonce_odr hidden swiftcc void @"$s20exportImplementation20unreferencedFunctionyyF"() {{.*}} { + +// In non-WMO mode, both functions must be emitted since they could be +// referenced from other translation units. + +// PRIMARY-LABEL: define weak_odr hidden swiftcc void @"$s20exportImplementation18referencedFunctionyyF"() {{.*}} { +// PRIMARY-LABEL: define weak_odr hidden swiftcc void @"$s20exportImplementation20unreferencedFunctionyyF"() {{.*}} { + +@export(implementation) public func referencedFunction() {} +@export(implementation) public func unreferencedFunction() {} + +public func referencesFunction() { + referencedFunction() +} diff --git a/test/Sema/access-level-and-implementation-only-import-embedded.swift b/test/Sema/access-level-and-implementation-only-import-embedded.swift index a70418774aa37..959b6ed106226 100644 --- a/test/Sema/access-level-and-implementation-only-import-embedded.swift +++ b/test/Sema/access-level-and-implementation-only-import-embedded.swift @@ -57,20 +57,20 @@ public func explicitlyInlinable(arg: StructFromDirect = StructFromDirect()) { public func implicitlyInlinablePublic(arg: StructFromDirect = StructFromDirect()) { // expected-error @-1 {{initializer 'init()' is internal and cannot be referenced from a default argument value}} // expected-error @-2 {{struct 'StructFromDirect' is internal and cannot be referenced from a default argument value}} -// expected-error @-3 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} +// expected-error @-3 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} // expected-error @-4 {{function cannot be declared public because its parameter uses an internal type}} // expected-note @-5 {{struct 'StructFromDirect' is imported by this file as 'internal' from 'directs'}} - _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} - // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} if (true) { - _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} - // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} } func nested() { - _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} - // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} } nested() @@ -83,19 +83,19 @@ public func implicitlyInlinablePublic(arg: StructFromDirect = StructFromDirect() } private func implicitlyInlinablePrivate(arg: StructFromDirect = StructFromDirect()) { -// expected-error @-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} +// expected-error @-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} // expected-note @-2 {{global function 'implicitlyInlinablePrivate(arg:)' is not '@usableFromInline' or public}} - _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} - // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} if (true) { - _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} - // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} } func nested() { - _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} - // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} } nested() @@ -107,7 +107,7 @@ private func implicitlyInlinablePrivate(arg: StructFromDirect = StructFromDirect explicitNonInliable() } -@_neverEmitIntoClient +@export(interface) public func explicitNonInliable(arg: StructFromDirect = StructFromDirect()) { // expected-error @-1 {{initializer 'init()' is internal and cannot be referenced from a default argument value}} // expected-error @-2 {{struct 'StructFromDirect' is internal and cannot be referenced from a default argument value}} @@ -120,7 +120,7 @@ public func explicitNonInliable(arg: StructFromDirect = StructFromDirect()) { _ = StructFromDirect() } - @_neverEmitIntoClient + @export(interface) func nested() { _ = StructFromDirect() } @@ -134,7 +134,7 @@ public func explicitNonInliable(arg: StructFromDirect = StructFromDirect()) { explicitNonInliable() } -@_neverEmitIntoClient +@export(interface) internal func explicitNonInliableInternal(arg: StructFromDirect = StructFromDirect()) { _ = StructFromDirect() @@ -142,7 +142,7 @@ internal func explicitNonInliableInternal(arg: StructFromDirect = StructFromDire _ = StructFromDirect() } - @_neverEmitIntoClient + @export(interface) func nested() { _ = StructFromDirect() } diff --git a/test/Sema/access-level-import-embedded.swift b/test/Sema/access-level-import-embedded.swift index 394dcc4f40be4..9d02998800bfc 100644 --- a/test/Sema/access-level-import-embedded.swift +++ b/test/Sema/access-level-import-embedded.swift @@ -102,7 +102,7 @@ internal func implicitlyInlinablePrivate(arg: StructFromDirect = StructFromDirec explicitNonInliable() } -@_neverEmitIntoClient +@export(interface) public func explicitNonInliable(arg: StructFromDirect = StructFromDirect()) { // expected-error @-1 {{initializer 'init()' is internal and cannot be referenced from a default argument value}} // expected-error @-2 {{struct 'StructFromDirect' is internal and cannot be referenced from a default argument value}} @@ -114,7 +114,7 @@ public func explicitNonInliable(arg: StructFromDirect = StructFromDirect()) { _ = StructFromDirect() } - @_neverEmitIntoClient + @export(interface) func nested() { _ = StructFromDirect() } @@ -128,7 +128,7 @@ public func explicitNonInliable(arg: StructFromDirect = StructFromDirect()) { explicitNonInliable() } -@_neverEmitIntoClient +@export(interface) internal func explicitNonInliableInternal(arg: StructFromDirect = StructFromDirect()) { _ = StructFromDirect() @@ -136,7 +136,7 @@ internal func explicitNonInliableInternal(arg: StructFromDirect = StructFromDire _ = StructFromDirect() } - @_neverEmitIntoClient + @export(interface) func nested() { _ = StructFromDirect() } diff --git a/test/Sema/hidden-memory-layout.swift b/test/Sema/hidden-memory-layout.swift index 1e6e53b2c5b1c..a3699533bc989 100644 --- a/test/Sema/hidden-memory-layout.swift +++ b/test/Sema/hidden-memory-layout.swift @@ -22,7 +22,7 @@ // RUN: -enable-experimental-feature CheckImplementationOnly /// Embedded -/// Will also show errors in non-@_neverEmitIntoClient functions. +/// Will also show errors in non-never-emit-into-client functions. // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module -o %t/indirects.swiftmodule \ @@ -144,27 +144,27 @@ public func implicitlyInlinablePublic() { let _: ExposedLayoutPublic = ExposedLayoutPublic() let _: ExposedLayoutPrivate = ExposedLayoutPrivate() let _: HiddenLayout = HiddenLayout() - // expected-embedded-opt-in-error @-1 2 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'HiddenLayout' is marked '@_implementationOnly'}} + // expected-embedded-opt-in-error @-1 2 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@export(interface)' because 'HiddenLayout' is marked '@_implementationOnly'}} let _: ExposedEnumPublic = ExposedEnumPublic.A let _: ExposedEnumPrivate = ExposedEnumPrivate.A let _: HiddenEnum = HiddenEnum.A - // expected-embedded-opt-in-error @-1 2 {{enum 'HiddenEnum' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'HiddenEnum' is marked '@_implementationOnly'}} + // expected-embedded-opt-in-error @-1 2 {{enum 'HiddenEnum' cannot be used in an embedded function not marked '@export(interface)' because 'HiddenEnum' is marked '@_implementationOnly'}} } private func implicitlyInlinablePrivate() { let _: ExposedLayoutPublic = ExposedLayoutPublic() let _: ExposedLayoutPrivate = ExposedLayoutPrivate() let _: HiddenLayout = HiddenLayout() - // expected-embedded-opt-in-error @-1 2 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'HiddenLayout' is marked '@_implementationOnly'}} + // expected-embedded-opt-in-error @-1 2 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@export(interface)' because 'HiddenLayout' is marked '@_implementationOnly'}} let _: ExposedEnumPublic = ExposedEnumPublic.A let _: ExposedEnumPrivate = ExposedEnumPrivate.A let _: HiddenEnum = HiddenEnum.A - // expected-embedded-opt-in-error @-1 2 {{enum 'HiddenEnum' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'HiddenEnum' is marked '@_implementationOnly'}} + // expected-embedded-opt-in-error @-1 2 {{enum 'HiddenEnum' cannot be used in an embedded function not marked '@export(interface)' because 'HiddenEnum' is marked '@_implementationOnly'}} } -@_neverEmitIntoClient +@export(interface) public func explicitNonInliable() { let _: ExposedLayoutPublic = ExposedLayoutPublic() let _: ExposedLayoutPrivate = ExposedLayoutPrivate() @@ -174,7 +174,7 @@ public func explicitNonInliable() { let _: HiddenEnum = HiddenEnum.A } -@_neverEmitIntoClient +@export(interface) internal func explicitNonInliableInternal() { let _: ExposedLayoutPublic = ExposedLayoutPublic() let _: ExposedLayoutPrivate = ExposedLayoutPrivate() @@ -208,7 +208,7 @@ public struct ExposedLayoutPublicUser: ProtocolFromDirect { // expected-opt-in-error @-1 {{cannot use enum 'HiddenEnum' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'HiddenEnum' is marked '@_implementationOnly'}} private func privateFunc(h: HiddenLayout) {} - // expected-embedded-opt-in-error @-1 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'HiddenLayout' is marked '@_implementationOnly'}} + // expected-embedded-opt-in-error @-1 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@export(interface)' because 'HiddenLayout' is marked '@_implementationOnly'}} } internal struct ExposedLayoutInternalUser: ProtocolFromDirect { @@ -229,7 +229,7 @@ internal struct ExposedLayoutInternalUser: ProtocolFromDirect { // expected-opt-in-error @-1 {{cannot use enum 'HiddenEnum' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'HiddenEnum' is marked '@_implementationOnly'}} private func privateFunc(h: HiddenLayout) {} - // expected-embedded-opt-in-error @-1 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'HiddenLayout' is marked '@_implementationOnly'}} + // expected-embedded-opt-in-error @-1 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@export(interface)' because 'HiddenLayout' is marked '@_implementationOnly'}} } private struct ExposedLayoutPrivateUser: ProtocolFromDirect { @@ -250,7 +250,7 @@ private struct ExposedLayoutPrivateUser: ProtocolFromDirect { // expected-opt-in-error @-1 {{cannot use enum 'HiddenEnum' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'HiddenEnum' is marked '@_implementationOnly'}} private func privateFunc(h: HiddenLayout) {} - // expected-embedded-opt-in-error @-1 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'HiddenLayout' is marked '@_implementationOnly'}} + // expected-embedded-opt-in-error @-1 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@export(interface)' because 'HiddenLayout' is marked '@_implementationOnly'}} } #if UseImplementationOnly @@ -266,7 +266,7 @@ private struct HiddenLayoutUser { private var e: ExposedEnumPrivate private var f: HiddenEnum - @_neverEmitIntoClient + @export(interface) private func privateFunc(h: HiddenLayout) {} } @@ -356,7 +356,7 @@ public class PublicClass: ProtocolFromDirect { private var f: HiddenEnum // expected-opt-in-error @-1 {{cannot use enum 'HiddenEnum' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'HiddenEnum' is marked '@_implementationOnly'}} - @_neverEmitIntoClient + @export(interface) private func privateFunc(h: HiddenLayout) {} } @@ -381,7 +381,7 @@ internal class InternalClass: ProtocolFromDirect { private var f: HiddenEnum // expected-opt-in-error @-1 {{cannot use enum 'HiddenEnum' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'HiddenEnum' is marked '@_implementationOnly'}} - private func privateFunc(h: HiddenLayout) {} // expected-embedded-opt-in-error {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'HiddenLayout' is marked '@_implementationOnly'}} + private func privateFunc(h: HiddenLayout) {} // expected-embedded-opt-in-error {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@export(interface)' because 'HiddenLayout' is marked '@_implementationOnly'}} } private class PrivateClass: ProtocolFromDirect { @@ -405,7 +405,7 @@ private class PrivateClass: ProtocolFromDirect { private var f: HiddenEnum // expected-opt-in-error @-1 {{cannot use enum 'HiddenEnum' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'HiddenEnum' is marked '@_implementationOnly'}} - private func privateFunc(h: HiddenLayout) {} // expected-embedded-opt-in-error {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'HiddenLayout' is marked '@_implementationOnly'}} + private func privateFunc(h: HiddenLayout) {} // expected-embedded-opt-in-error {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@export(interface)' because 'HiddenLayout' is marked '@_implementationOnly'}} } #if UseImplementationOnly diff --git a/test/Sema/implementation-only-import-embedded.swift b/test/Sema/implementation-only-import-embedded.swift index cc2d1ce30653c..b404f349da058 100644 --- a/test/Sema/implementation-only-import-embedded.swift +++ b/test/Sema/implementation-only-import-embedded.swift @@ -57,19 +57,19 @@ public func explicitlyInlinable(arg: StructFromDirect = StructFromDirect()) { public func implicitlyInlinablePublic(arg: StructFromDirect = StructFromDirect()) { // expected-error @-1 {{initializer 'init()' cannot be used in a default argument value because 'directs' was imported implementation-only}} // expected-error @-2 {{struct 'StructFromDirect' cannot be used in a default argument value because 'directs' was imported implementation-only}} -// expected-error @-3 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} +// expected-error @-3 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} - _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} - // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} if (true) { - _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} - // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} } func nested() { - _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} - // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} } nested() @@ -85,24 +85,24 @@ public func implicitlyInlinablePublic(arg: StructFromDirect = StructFromDirect() localSPI() spiFunctionFromDirect() - let _: AliasToDirect // expected-error {{AliasToDirect' aliases 'directs.StructFromDirect' and cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' has been imported as implementation-only}} + let _: AliasToDirect // expected-error {{AliasToDirect' aliases 'directs.StructFromDirect' and cannot be used in an embedded function not marked '@export(interface)' because 'directs' has been imported as implementation-only}} } private func implicitlyInlinablePrivate(arg: StructFromDirect = StructFromDirect()) { -// expected-error @-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} +// expected-error @-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} // expected-note @-2 {{global function 'implicitlyInlinablePrivate(arg:)' is not '@usableFromInline' or public}} - _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} - // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} if (true) { - _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} - // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} } func nested() { - _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} - // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} } nested() @@ -114,7 +114,7 @@ private func implicitlyInlinablePrivate(arg: StructFromDirect = StructFromDirect explicitNonInliable() } -@_neverEmitIntoClient +@export(interface) public func explicitNonInliable(arg: StructFromDirect = StructFromDirect()) { // expected-error @-1 {{initializer 'init()' cannot be used in a default argument value because 'directs' was imported implementation-only}} // expected-error @-2 {{struct 'StructFromDirect' cannot be used in a default argument value because 'directs' was imported implementation-only}} @@ -139,7 +139,7 @@ public func explicitNonInliable(arg: StructFromDirect = StructFromDirect()) { explicitNonInliable() } -@_neverEmitIntoClient +@export(interface) internal func explicitNonInliableInternal(arg: StructFromDirect = StructFromDirect()) { _ = StructFromDirect() @@ -165,7 +165,7 @@ internal func explicitNonInliableInternal(arg: StructFromDirect = StructFromDire struct Accessors { public var var1: Int { get { - globalFunctionFromDirect() // expected-error {{global function 'globalFunctionFromDirect()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + globalFunctionFromDirect() // expected-error {{global function 'globalFunctionFromDirect()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} return 0 } } @@ -173,12 +173,12 @@ struct Accessors { @_alwaysEmitIntoClient public var var2: Int { get { - globalFunctionFromDirect() // expected-error {{global function 'globalFunctionFromDirect()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + globalFunctionFromDirect() // expected-error {{global function 'globalFunctionFromDirect()' cannot be used in an embedded function not marked '@export(interface)' because 'directs' was imported implementation-only}} return 0 } } - @_neverEmitIntoClient + @export(interface) public var var3: Int { get { globalFunctionFromDirect() @@ -187,7 +187,7 @@ struct Accessors { } public var var4: Int { - @_neverEmitIntoClient + @export(interface) get { globalFunctionFromDirect() return 0 diff --git a/test/Sema/restricted-import-embedded-inlinable-conformances.swift b/test/Sema/restricted-import-embedded-inlinable-conformances.swift index cf955055c68d4..4592c6d920177 100644 --- a/test/Sema/restricted-import-embedded-inlinable-conformances.swift +++ b/test/Sema/restricted-import-embedded-inlinable-conformances.swift @@ -43,7 +43,7 @@ func internalConformanceInTypealias() { _ = NormalProtoAssoc() // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}} } -@_neverEmitIntoClient +@export(interface) func internalConformanceInTypealiasNEIC() { let x: NormalProtoAssoc? = nil // okay _ = x @@ -70,7 +70,7 @@ func internalConformanceInBoundGeneric() { _ = NormalProtoAssocHolder(nil as NormalStruct?) // expected-ioi-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}} } -@_neverEmitIntoClient +@export(interface) func internalConformanceInBoundGenericNEIC() { let x: NormalProtoAssocHolder? = nil // okay _ = x @@ -90,7 +90,7 @@ func internalDowncast(_ x: Any) -> Bool { return normal || alias } -@_neverEmitIntoClient +@export(interface) func internalDowncastNEIC(_ x: Any) -> Bool { let normal = x is NormalProtoAssocHolder // okay let alias = x is NormalProtoAssoc // okay @@ -121,7 +121,7 @@ func internalSwitch(_ x: Any) { } } -@_neverEmitIntoClient +@export(interface) func internalSwitchNEIC(_ x: Any) { switch x { case let holder as NormalProtoAssocHolder: // okay @@ -152,7 +152,7 @@ func internalEnum() { _ = NormalProtoEnumUser.a // expected-ioi-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}} } -@_neverEmitIntoClient +@export(interface) func internalEnumNEIC() { let x: NormalProtoEnumUser = .a // okay _ = x @@ -169,7 +169,7 @@ func internalFunc() { testFuncImpl(NormalStruct.self) // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}} } -@_neverEmitIntoClient +@export(interface) func internalFuncNEIC() { testFuncImpl(NormalStruct.self) // okay } diff --git a/test/attr/export.swift b/test/attr/export.swift new file mode 100644 index 0000000000000..b92e60971cad2 --- /dev/null +++ b/test/attr/export.swift @@ -0,0 +1,24 @@ +// RUN: %target-typecheck-verify-swift + +@export(interface) +func f1() { } + +@export(implementation) +func f2() { } + +@export(nothing) // expected-error{{unknown option 'nothing' for attribute 'export'}} +func f3() { } + +@export // expected-error{{expected '(' in 'export' attribute}} +func f4() { } + +@export(interface) // expected-error{{'@export(interface)' cannot be used with '@usableFromInline'}} +@usableFromInline +func f5() { } + +@export(interface) // expected-error{{'@export(interface)' cannot be used with '@inlinable'}} +@inlinable +func f6() { } + +@_neverEmitIntoClient // expected-warning{{'@_neverEmitIntoClient' has been renamed to '@export(interface)'}}{{1-22=@export(interface)}} +func f7() { } diff --git a/test/embedded/deinit-noncopyable.swift b/test/embedded/deinit-noncopyable.swift index 2aa2b448c1989..0fb55a8b77539 100644 --- a/test/embedded/deinit-noncopyable.swift +++ b/test/embedded/deinit-noncopyable.swift @@ -19,7 +19,7 @@ } @inline(__always) - @_alwaysEmitIntoClient + @export(implementation) deinit { buffer.deinitialize().deallocate() } diff --git a/test/embedded/implementation-only-import-build.swift b/test/embedded/implementation-only-import-build.swift index 82b0b276deb03..97a0ec1a7b3ee 100644 --- a/test/embedded/implementation-only-import-build.swift +++ b/test/embedded/implementation-only-import-build.swift @@ -25,7 +25,7 @@ private func implicitlyInlinablePrivate() { localInternalFunc() } -@_neverEmitIntoClient +@export(interface) public func explicitNonInliable() { _ = StructFromDirect() @@ -33,7 +33,7 @@ public func explicitNonInliable() { _ = StructFromDirect() } - @_neverEmitIntoClient + @export(interface) func nested() { _ = StructFromDirect() } @@ -42,7 +42,7 @@ public func explicitNonInliable() { localInternalFunc() } -@_alwaysEmitIntoClient +@export(implementation) public func legalAccessToIndirect() { _ = StructFromIndirect() @@ -57,7 +57,7 @@ public func legalAccessToIndirect() { } extension Array { - @_alwaysEmitIntoClient + @export(implementation) public var myMutableSpan: Int { get { return 0 diff --git a/test/embedded/linkage/never_emit_into_client.swift b/test/embedded/linkage/export_interface.swift similarity index 95% rename from test/embedded/linkage/never_emit_into_client.swift rename to test/embedded/linkage/export_interface.swift index 83bdf8f5ce388..b8c1f8ccc9fda 100644 --- a/test/embedded/linkage/never_emit_into_client.swift +++ b/test/embedded/linkage/export_interface.swift @@ -21,7 +21,7 @@ //--- Library.swift // LIBRARY-IR: define {{(protected |dllexport )?}}swiftcc ptr @"$e7Library5helloSaySiGyF"() -@_neverEmitIntoClient +@export(interface) public func hello() -> [Int] { getArray() } @@ -52,7 +52,7 @@ public func unnecessary() -> Int { 5 } //--- Application.swift import Library -@_neverEmitIntoClient +@export(interface) public func testMe() { _ = hello() _ = getArray() @@ -64,8 +64,8 @@ public func testMe() { // APPLICATION-SIL: sil @$e7Library5helloSaySiGyF : $@convention(thin) () -> @owned Array{{$}} // APPLICATION-IR: declare swiftcc ptr @"$e7Library5helloSaySiGyF"() -// Note: "getArray" is not @_neverEmitIntoClient, so it's definition is -// available. +// Note: "getArray" is not prohibited from being emitted into the client, so +// its definition is available. // APPLICATION-SIL: sil public_external @$e7Library8getArraySaySiGyF : $@convention(thin) () -> @owned Array { // APPLICATION-IR: define linkonce_odr hidden swiftcc ptr @"$e7Library8getArraySaySiGyF"() diff --git a/test/embedded/linkage/implementation_only_hiding.swift b/test/embedded/linkage/implementation_only_hiding.swift index a987f75925594..435c0964e63e1 100644 --- a/test/embedded/linkage/implementation_only_hiding.swift +++ b/test/embedded/linkage/implementation_only_hiding.swift @@ -28,7 +28,7 @@ // RUN: rm -rf %t/Dependencies // Build the application against the library. This is expected to work because -// @_neverEmitIntoClient hides the body of test(). +// @export(interface) hides the body of test(). // RUN: %target-swift-frontend -emit-ir -parse-as-library %t/Files/Application.swift -enable-experimental-feature Embedded -I %t/Modules -o %t/Application.ir // REQUIRES: swift_in_compiler @@ -38,7 +38,7 @@ @_implementationOnly import CDependency // expected-warning {{using '@_implementationOnly' without enabling library evolution for 'Library' may lead to instability during execution}} @_implementationOnly import SwiftDependency // expected-warning {{using '@_implementationOnly' without enabling library evolution for 'Library' may lead to instability during execution}} -@_neverEmitIntoClient +@export(interface) public func test() { _ = getPoint(3.14159, 2.71828) A().doSomething() @@ -46,13 +46,13 @@ public func test() { #if BAD_IOI_USAGE public func badCLibraryUsage() { - _ = getPoint(3.14159, 2.71828) // expected-error {{global function 'getPoint' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'CDependency' was imported implementation-only}} + _ = getPoint(3.14159, 2.71828) // expected-error {{global function 'getPoint' cannot be used in an embedded function not marked '@export(interface)' because 'CDependency' was imported implementation-only}} } public func badSwiftLibraryUsage() { - A().doSomething() // expected-error {{struct 'A' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'SwiftDependency' was imported implementation-only}} - // expected-error @-1 {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'SwiftDependency' was imported implementation-only}} - // expected-error @-2 {{instance method 'doSomething()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'SwiftDependency' was imported implementation-only}} + A().doSomething() // expected-error {{struct 'A' cannot be used in an embedded function not marked '@export(interface)' because 'SwiftDependency' was imported implementation-only}} + // expected-error @-1 {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'SwiftDependency' was imported implementation-only}} + // expected-error @-2 {{instance method 'doSomething()' cannot be used in an embedded function not marked '@export(interface)' because 'SwiftDependency' was imported implementation-only}} } #endif diff --git a/test/embedded/linkage/leaf_application.swift b/test/embedded/linkage/leaf_application.swift index 8d6debacd6303..14912315fff6d 100644 --- a/test/embedded/linkage/leaf_application.swift +++ b/test/embedded/linkage/leaf_application.swift @@ -53,7 +53,7 @@ private func throughPrivate() -> [Int] { public func unnecessary() -> Int64 { 5 } // LIBRARY-IR: define {{.*}} @"$e7Library14unusedYetThere -@_neverEmitIntoClient +@export(interface) public func unusedYetThere() -> Int64 { 5 } open class PointClass { @@ -81,7 +81,7 @@ extension PointClass: Reflectable { } // LIBRARY-IR: define {{.*}} @"$e7Library18createsExistentialAA11Reflectable_pyF"() -@_neverEmitIntoClient +@export(interface) public func createsExistential() -> any Reflectable { return PointClass(x: 5, y: 5) }