Skip to content

Define a feature for _specialize with availability #39966

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion include/swift/AST/ASTPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,9 @@ void getInheritedForPrinting(
StringRef getAccessorKindString(AccessorKind value);

bool printCompatibilityFeatureChecksPre(ASTPrinter &printer, Decl *decl);
void printCompatibilityFeatureChecksPost(ASTPrinter &printer);
void printCompatibilityFeatureChecksPost(
ASTPrinter &printer,
llvm::function_ref<void()> printElse = []() -> void {});

} // namespace swift

Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1369,7 +1369,7 @@ class SpecializeAttr final
numSPIGroups };
}

ArrayRef<AvailableAttr *> getAvailabeAttrs() const {
ArrayRef<AvailableAttr *> getAvailableAttrs() const {
return {this->template getTrailingObjects<AvailableAttr *>(),
numAvailableAttrs};
}
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,10 @@ struct PrintOptions {
/// compilers that might parse the result.
bool PrintCompatibilityFeatureChecks = false;

/// Whether to print @_specialize attributes that have an availability
/// parameter.
bool PrintSpecializeAttributeWithAvailability = true;

/// \see ShouldQualifyNestedDeclarations
enum class QualifyNestedDeclarations {
Never,
Expand Down
1 change: 1 addition & 0 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,6 @@ LANGUAGE_FEATURE(BuiltinBuildMainExecutor, 0, "MainActor executor building built
LANGUAGE_FEATURE(BuiltinCreateAsyncTaskInGroup, 0, "MainActor executor building builtin", true)
LANGUAGE_FEATURE(BuiltinMove, 0, "Builtin.move()", true)
LANGUAGE_FEATURE(BuiltinCopy, 0, "Builtin.copy()", true)
LANGUAGE_FEATURE(SpecializeAttributeWithAvailability, 0, "@_specialize attribute with availability", true)

#undef LANGUAGE_FEATURE
33 changes: 30 additions & 3 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ static bool willUseTypeReprPrinting(TypeLoc tyLoc,
(tyLoc.getType().isNull() && tyLoc.getTypeRepr()));
}

static std::vector<Feature> getUniqueFeaturesUsed(Decl *decl);
namespace {
/// AST pretty-printer.
class PrintAST : public ASTVisitor<PrintAST> {
Expand Down Expand Up @@ -1003,7 +1004,22 @@ class PrintAST : public ASTVisitor<PrintAST> {
ASTVisitor::visit(D);

if (haveFeatureChecks) {
printCompatibilityFeatureChecksPost(Printer);

printCompatibilityFeatureChecksPost(Printer, [&]() -> void {
auto features = getUniqueFeaturesUsed(D);
assert(!features.empty());
if (std::find_if(features.begin(), features.end(),
[](Feature feature) -> bool {
return getFeatureName(feature).equals(
"SpecializeAttributeWithAvailability");
}) != features.end()) {
Printer << "#else\n";
Options.PrintSpecializeAttributeWithAvailability = false;
ASTVisitor::visit(D);
Options.PrintSpecializeAttributeWithAvailability = true;
Printer.printNewline();
}
});
}

if (Synthesize) {
Expand Down Expand Up @@ -2818,6 +2834,16 @@ static bool usesFeatureBuiltinMove(Decl *decl) {

static bool usesFeatureBuiltinCopy(Decl *decl) { return false; }

static bool usesFeatureSpecializeAttributeWithAvailability(Decl *decl) {
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
for (auto specialize : func->getAttrs().getAttributes<SpecializeAttr>()) {
if (!specialize->getAvailableAttrs().empty())
return true;
}
}
return false;
}

static bool usesFeatureInheritActorContext(Decl *decl) {
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
for (auto param : *func->getParameters()) {
Expand Down Expand Up @@ -2926,12 +2952,13 @@ bool swift::printCompatibilityFeatureChecksPre(
return true;
}

void swift::printCompatibilityFeatureChecksPost(ASTPrinter &printer) {
void swift::printCompatibilityFeatureChecksPost(
ASTPrinter &printer, llvm::function_ref<void()> printElse) {
printer.printNewline();
printElse();
printer << "#endif\n";
}


void PrintAST::visitExtensionDecl(ExtensionDecl *decl) {
if (Options.TransformContext &&
Options.TransformContext->isPrintingSynthesizedExtension()) {
Expand Down
8 changes: 7 additions & 1 deletion lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,12 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
if (!Options.PrintSPIs && !attr->getSPIGroups().empty())
return false;

// Don't print the _specialize attribute if we are asked to skip the ones
// with availability parameters.
if (!Options.PrintSpecializeAttributeWithAvailability &&
!attr->getAvailableAttrs().empty())
return false;

Printer << "@" << getAttrName() << "(";
auto exported = attr->isExported() ? "true" : "false";
auto kind = attr->isPartialSpecialization() ? "partial" : "full";
Expand All @@ -993,7 +999,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
Printer << "kind: " << kind << ", ";
if (target)
Printer << "target: " << target << ", ";
auto availAttrs = attr->getAvailabeAttrs();
auto availAttrs = attr->getAvailableAttrs();
if (!availAttrs.empty()) {
Printer << "availability: ";
auto numAttrs = availAttrs.size();
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/Availability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ AvailabilityInference::annotatedAvailableRangeForAttr(const SpecializeAttr* attr

const AvailableAttr *bestAvailAttr = nullptr;

for (auto *availAttr : attr->getAvailabeAttrs()) {
for (auto *availAttr : attr->getAvailableAttrs()) {
if (availAttr == nullptr || !availAttr->Introduced.hasValue() ||
!availAttr->isActivePlatform(ctx) ||
availAttr->isLanguageVersionSpecific() ||
Expand Down
4 changes: 2 additions & 2 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2611,14 +2611,14 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
auto numSPIGroups = attr->getSPIGroups().size();
assert(pieces.size() == numArgs + numSPIGroups ||
pieces.size() == (numArgs - 1 + numSPIGroups));
auto numAvailabilityAttrs = attr->getAvailabeAttrs().size();
auto numAvailabilityAttrs = attr->getAvailableAttrs().size();
SpecializeDeclAttrLayout::emitRecord(
S.Out, S.ScratchRecord, abbrCode, (unsigned)attr->isExported(),
(unsigned)attr->getSpecializationKind(),
S.addGenericSignatureRef(attr->getSpecializedSignature()),
S.addDeclRef(targetFunDecl), numArgs, numSPIGroups,
numAvailabilityAttrs, pieces);
for (auto availAttr : attr->getAvailabeAttrs()) {
for (auto availAttr : attr->getAvailableAttrs()) {
writeDeclAttribute(D, availAttr);
}
return;
Expand Down
10 changes: 10 additions & 0 deletions test/ModuleInterface/features.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@
// the uses of those features are guarded by appropriate #if's that allow older
// compilers to skip over the uses of newer features.

// CHECK: #if compiler(>=5.3) && $SpecializeAttributeWithAvailability
// CHECK: @_specialize(exported: true, kind: full, availability: macOS, introduced: 12; where T == Swift.Int)
// CHECK: public func specializeWithAvailability<T>(_ t: T)
// CHECK: #else
// CHECK: public func specializeWithAvailability<T>(_ t: T)
// CHECK: #endif
@_specialize(exported: true, availability: macOS 12, *; where T == Int)
public func specializeWithAvailability<T>(_ t: T) {
}

// CHECK: #if compiler(>=5.3) && $Actors
// CHECK-NEXT: public actor MyActor
// CHECK: @_semantics("defaultActor") nonisolated final public var unownedExecutor: _Concurrency.UnownedSerialExecutor {
Expand Down