Skip to content

AST: Introduce @_disallowFeatureSuppression attribute #72604

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
merged 2 commits into from
Mar 27, 2024
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
3 changes: 2 additions & 1 deletion include/swift/AST/ASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -483,12 +483,13 @@ BridgedAlignmentAttr_createParsed(BridgedASTContext cContext,
BridgedSourceLoc cAtLoc,
BridgedSourceRange cRange, size_t cValue);

SWIFT_NAME("BridgedAllowFeatureSuppressionAttr.createParsed(_:atLoc:range:features:)")
SWIFT_NAME("BridgedAllowFeatureSuppressionAttr.createParsed(_:atLoc:range:inverted:features:)")
BridgedAllowFeatureSuppressionAttr
BridgedAllowFeatureSuppressionAttr_createParsed(
BridgedASTContext cContext,
BridgedSourceLoc cAtLoc,
BridgedSourceRange cRange,
bool inverted,
BridgedArrayRef cFeatures);

SWIFT_NAME("BridgedCDeclAttr.createParsed(_:atLoc:range:name:)")
Expand Down
15 changes: 10 additions & 5 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,11 @@ class DeclAttribute : public AttributeBase {
isUnsafe : 1
);

SWIFT_INLINE_BITFIELD_FULL(AllowFeatureSuppressionAttr, DeclAttribute, 32,
SWIFT_INLINE_BITFIELD_FULL(AllowFeatureSuppressionAttr, DeclAttribute, 1+31,
: NumPadBits,
NumFeatures : 32
Inverted : 1,

NumFeatures : 31
);
} Bits;
// clang-format on
Expand Down Expand Up @@ -2628,14 +2630,17 @@ class AllowFeatureSuppressionAttr final
private llvm::TrailingObjects<AllowFeatureSuppressionAttr, Identifier> {
friend TrailingObjects;

/// Create an implicit @objc attribute with the given (optional) name.
AllowFeatureSuppressionAttr(SourceLoc atLoc, SourceRange range,
bool implicit, ArrayRef<Identifier> features);
AllowFeatureSuppressionAttr(SourceLoc atLoc, SourceRange range, bool implicit,
bool inverted, ArrayRef<Identifier> features);

public:
static AllowFeatureSuppressionAttr *create(ASTContext &ctx, SourceLoc atLoc,
SourceRange range, bool implicit,
bool inverted,
ArrayRef<Identifier> features);

bool getInverted() const { return Bits.AllowFeatureSuppressionAttr.Inverted; }

ArrayRef<Identifier> getSuppressedFeatures() const {
return {getTrailingObjects<Identifier>(),
Bits.AllowFeatureSuppressionAttr.NumFeatures};
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/DeclAttr.def
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,7 @@ SIMPLE_DECL_ATTR(_noObjCBridging, NoObjCBridging,
DECL_ATTR(_allowFeatureSuppression, AllowFeatureSuppression,
OnAnyDecl | UserInaccessible | NotSerialized | ABIStableToAdd | APIStableToAdd | ABIStableToRemove | APIStableToRemove,
157)
DECL_ATTR_ALIAS(_disallowFeatureSuppression, AllowFeatureSuppression)
SIMPLE_DECL_ATTR(_preInverseGenerics, PreInverseGenerics,
OnAbstractFunction | OnSubscript | OnVar | OnExtension | UserInaccessible | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
158)
Expand Down
5 changes: 5 additions & 0 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
// imply the existence of earlier features. (This only needs to apply to
// suppressible features.)
//
// Sometimes, certain declarations will conflict with existing declarations
// when printed with a suppressible feature disabled. The attribute
// @_disallowFeatureSuppression can be used to suppress feature suppression on
// a particular declaration.
//
// If suppressing a feature in general is problematic, but it's okay to
// suppress it for specific declarations, the feature can be made
// conditionally suppressible. Declarations opt in to suppression with
Expand Down
3 changes: 2 additions & 1 deletion include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1157,7 +1157,8 @@ class Parser {
std::optional<AccessLevel> &Visibility);

ParserResult<AllowFeatureSuppressionAttr>
parseAllowFeatureSuppressionAttribute(SourceLoc atLoc, SourceLoc loc);
parseAllowFeatureSuppressionAttribute(bool inverted, SourceLoc atLoc,
SourceLoc loc);

/// Parse the @attached or @freestanding attribute that specifies a macro
/// role.
Expand Down
6 changes: 4 additions & 2 deletions lib/AST/ASTBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,12 +433,14 @@ BridgedAllowFeatureSuppressionAttr
BridgedAllowFeatureSuppressionAttr_createParsed(BridgedASTContext cContext,
BridgedSourceLoc cAtLoc,
BridgedSourceRange cRange,
bool inverted,
BridgedArrayRef cFeatures) {
SmallVector<Identifier> features;
for (auto elem : cFeatures.unbridged<BridgedIdentifier>())
features.push_back(elem.unbridged());
return AllowFeatureSuppressionAttr::create(cContext.unbridged(),
cAtLoc.unbridged(), cRange.unbridged(), /*implicit*/ false, features);
return AllowFeatureSuppressionAttr::create(
cContext.unbridged(), cAtLoc.unbridged(), cRange.unbridged(),
/*implicit*/ false, inverted, features);
}

BridgedCDeclAttr BridgedCDeclAttr_createParsed(BridgedASTContext cContext,
Expand Down
41 changes: 24 additions & 17 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1275,14 +1275,17 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
Printer << "(" << cast<AlignmentAttr>(this)->getValue() << ")";
break;

case DeclAttrKind::AllowFeatureSuppression:
Printer.printAttrName("@_allowFeatureSuppression");
case DeclAttrKind::AllowFeatureSuppression: {
auto Attr = cast<AllowFeatureSuppressionAttr>(this);
Printer.printAttrName(Attr->getInverted() ? "@_disallowFeatureSuppression"
: "@_allowFeatureSuppression");
Printer << "(";
interleave(cast<AllowFeatureSuppressionAttr>(this)->getSuppressedFeatures(),
[&](Identifier ident) { Printer << ident; },
[&] { Printer << ", "; });
interleave(
Attr->getSuppressedFeatures(),
[&](Identifier ident) { Printer << ident; }, [&] { Printer << ", "; });
Printer << ")";
break;
}

case DeclAttrKind::SILGenName:
Printer.printAttrName("@_silgen_name");
Expand Down Expand Up @@ -1947,7 +1950,11 @@ StringRef DeclAttribute::getAttrName() const {
case DeclAttrKind::Extern:
return "_extern";
case DeclAttrKind::AllowFeatureSuppression:
return "_allowFeatureSuppression";
if (cast<AllowFeatureSuppressionAttr>(this)->getInverted()) {
return "_disallowFeatureSuppression";
} else {
return "_allowFeatureSuppression";
}
}
llvm_unreachable("bad DeclAttrKind");
}
Expand Down Expand Up @@ -2932,24 +2939,24 @@ StorageRestrictionsAttr::getAccessesProperties(AccessorDecl *attachedTo) const {
{});
}

AllowFeatureSuppressionAttr::AllowFeatureSuppressionAttr(SourceLoc atLoc,
SourceRange range,
bool implicit,
ArrayRef<Identifier> features)
: DeclAttribute(DeclAttrKind::AllowFeatureSuppression,
atLoc, range, implicit) {
AllowFeatureSuppressionAttr::AllowFeatureSuppressionAttr(
SourceLoc atLoc, SourceRange range, bool implicit, bool inverted,
ArrayRef<Identifier> features)
: DeclAttribute(DeclAttrKind::AllowFeatureSuppression, atLoc, range,
implicit) {
Bits.AllowFeatureSuppressionAttr.Inverted = inverted;
Bits.AllowFeatureSuppressionAttr.NumFeatures = features.size();
std::uninitialized_copy(features.begin(), features.end(),
getTrailingObjects<Identifier>());
}

AllowFeatureSuppressionAttr *
AllowFeatureSuppressionAttr::create(ASTContext &ctx, SourceLoc atLoc,
SourceRange range, bool implicit,
ArrayRef<Identifier> features) {
AllowFeatureSuppressionAttr *AllowFeatureSuppressionAttr::create(
ASTContext &ctx, SourceLoc atLoc, SourceRange range, bool implicit,
bool inverted, ArrayRef<Identifier> features) {
unsigned size = totalSizeToAlloc<Identifier>(features.size());
auto *mem = ctx.Allocate(size, alignof(AllowFeatureSuppressionAttr));
return new (mem) AllowFeatureSuppressionAttr(atLoc, range, implicit, features);
return new (mem)
AllowFeatureSuppressionAttr(atLoc, range, implicit, inverted, features);
}

void swift::simple_display(llvm::raw_ostream &out, const DeclAttribute *attr) {
Expand Down
27 changes: 22 additions & 5 deletions lib/AST/FeatureSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,9 +695,14 @@ void FeatureSet::collectSuppressibleFeature(Feature feature,
operation == Insert);
}

static bool shouldSuppressFeature(StringRef featureName, Decl *decl) {
static bool hasFeatureSuppressionAttribute(Decl *decl, StringRef featureName,
bool inverted) {
auto attr = decl->getAttrs().getAttribute<AllowFeatureSuppressionAttr>();
if (!attr) return false;
if (!attr)
return false;

if (attr->getInverted() != inverted)
return false;

for (auto suppressedFeature : attr->getSuppressedFeatures()) {
if (suppressedFeature.is(featureName))
Expand All @@ -707,6 +712,14 @@ static bool shouldSuppressFeature(StringRef featureName, Decl *decl) {
return false;
}

static bool disallowFeatureSuppression(StringRef featureName, Decl *decl) {
return hasFeatureSuppressionAttribute(decl, featureName, true);
}

static bool allowFeatureSuppression(StringRef featureName, Decl *decl) {
return hasFeatureSuppressionAttribute(decl, featureName, false);
}

/// Go through all the features used by the given declaration and
/// either add or remove them to this set.
void FeatureSet::collectFeaturesUsed(Decl *decl, InsertOrRemove operation) {
Expand All @@ -716,11 +729,15 @@ void FeatureSet::collectFeaturesUsed(Decl *decl, InsertOrRemove operation) {
if (usesFeature##FeatureName(decl)) \
collectRequiredFeature(Feature::FeatureName, operation);
#define SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
if (usesFeature##FeatureName(decl)) \
collectSuppressibleFeature(Feature::FeatureName, operation);
if (usesFeature##FeatureName(decl)) { \
if (disallowFeatureSuppression(#FeatureName, decl)) \
collectRequiredFeature(Feature::FeatureName, operation); \
else \
collectSuppressibleFeature(Feature::FeatureName, operation); \
}
#define CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
if (usesFeature##FeatureName(decl)) { \
if (shouldSuppressFeature(#FeatureName, decl)) \
if (allowFeatureSuppression(#FeatureName, decl)) \
collectSuppressibleFeature(Feature::FeatureName, operation); \
else \
collectRequiredFeature(Feature::FeatureName, operation); \
Expand Down
13 changes: 12 additions & 1 deletion lib/ASTGen/Sources/ASTGen/DeclAttrs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,16 @@ extension ASTGenVisitor {
return nil
}

let inverted: Bool
switch node.attributeName {
case "_allowFeatureSuppression":
inverted = false
case "_disallowFeatureSuppression":
inverted = true
default:
return nil
}

let features = args.compactMap(in: self) { arg -> BridgedIdentifier? in
guard arg.label == nil,
let declNameExpr = arg.expression.as(DeclReferenceExprSyntax.self),
Expand All @@ -361,6 +371,7 @@ extension ASTGenVisitor {
self.ctx,
atLoc: self.generateSourceLoc(node.atSign),
range: self.generateSourceRange(node),
inverted: inverted,
features: features)
}

Expand Down Expand Up @@ -388,7 +399,7 @@ extension ASTGenVisitor {

func generateAvailableAttr(attribute node: AttributeSyntax) -> [BridgedAvailableAttr] {
guard
// `@_OriginallyDefinedIn` has special argument list syntax.
// `@available` has special argument list syntax.
let args = node.arguments?.as(AvailabilityArgumentListSyntax.self)
else {
// TODO: Diagnose.
Expand Down
15 changes: 9 additions & 6 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2461,8 +2461,10 @@ Parser::parseDocumentationAttribute(SourceLoc atLoc, SourceLoc loc) {
}

ParserResult<AllowFeatureSuppressionAttr>
Parser::parseAllowFeatureSuppressionAttribute(SourceLoc atLoc, SourceLoc loc) {
StringRef attrName = "_allowFeatureSuppression";
Parser::parseAllowFeatureSuppressionAttribute(bool inverted, SourceLoc atLoc,
SourceLoc loc) {
StringRef attrName =
inverted ? "_disallowFeatureSuppression" : "_allowFeatureSuppression";

SmallVector<Identifier, 4> features;
SourceRange parensRange;
Expand All @@ -2479,9 +2481,9 @@ Parser::parseAllowFeatureSuppressionAttribute(SourceLoc atLoc, SourceLoc loc) {
return status;

auto range = SourceRange(loc, parensRange.End);
return makeParserResult(
AllowFeatureSuppressionAttr::create(Context, loc, range, /*implicit*/ false,
features));
return makeParserResult(AllowFeatureSuppressionAttr::create(
Context, loc, range, /*implicit*/ false, /*inverted*/ inverted,
features));
}

static std::optional<MacroIntroducedDeclNameKind>
Expand Down Expand Up @@ -3900,7 +3902,8 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
break;
}
case DeclAttrKind::AllowFeatureSuppression: {
auto Attr = parseAllowFeatureSuppressionAttribute(AtLoc, Loc);
auto inverted = (AttrName == "_disallowFeatureSuppression");
auto Attr = parseAllowFeatureSuppressionAttribute(inverted, AtLoc, Loc);
Status |= Attr;
if (Attr.isNonNull())
Attributes.add(Attr.get());
Expand Down
16 changes: 0 additions & 16 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6034,22 +6034,6 @@ llvm::Error DeclDeserializer::deserializeDeclCommon() {
break;
}

case decls_block::AllowFeatureSuppression_DECL_ATTR: {
bool isImplicit;
ArrayRef<uint64_t> featureIds;
serialization::decls_block::AllowFeatureSuppressionDeclAttrLayout
::readRecord(scratch, isImplicit, featureIds);

SmallVector<Identifier, 4> features;
for (auto id : featureIds)
features.push_back(MF.getIdentifier(id));

Attr = AllowFeatureSuppressionAttr::create(ctx, SourceLoc(),
SourceRange(), isImplicit,
features);
break;
}

case decls_block::UnavailableFromAsync_DECL_ATTR: {
bool isImplicit;
serialization::decls_block::UnavailableFromAsyncDeclAttrLayout::
Expand Down
8 changes: 2 additions & 6 deletions lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -2138,12 +2138,6 @@ namespace decls_block {
BCArray<IdentifierIDField> // name components
>;

using AllowFeatureSuppressionDeclAttrLayout = BCRecordLayout<
AllowFeatureSuppression_DECL_ATTR,
BCFixed<1>, // implicit flag
BCArray<IdentifierIDField> // feature names
>;

using SPIAccessControlDeclAttrLayout = BCRecordLayout<
SPIAccessControl_DECL_ATTR,
BCArray<IdentifierIDField> // SPI names
Expand Down Expand Up @@ -2254,6 +2248,8 @@ namespace decls_block {
using ClangImporterSynthesizedTypeDeclAttrLayout
= BCRecordLayout<ClangImporterSynthesizedType_DECL_ATTR>;
using PrivateImportDeclAttrLayout = BCRecordLayout<PrivateImport_DECL_ATTR>;
using AllowFeatureSuppressionDeclAttrLayout =
BCRecordLayout<AllowFeatureSuppression_DECL_ATTR>;
using ProjectedValuePropertyDeclAttrLayout = BCRecordLayout<
ProjectedValueProperty_DECL_ATTR,
BCFixed<1>, // isImplicit
Expand Down
15 changes: 1 addition & 14 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2717,6 +2717,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
case DeclAttrKind::RestatedObjCConformance:
case DeclAttrKind::ClangImporterSynthesizedType:
case DeclAttrKind::PrivateImport:
case DeclAttrKind::AllowFeatureSuppression:
llvm_unreachable("cannot serialize attribute");

#define SIMPLE_DECL_ATTR(_, CLASS, ...) \
Expand Down Expand Up @@ -2769,20 +2770,6 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
return;
}

case DeclAttrKind::AllowFeatureSuppression: {
auto *theAttr = cast<AllowFeatureSuppressionAttr>(DA);
auto abbrCode =
S.DeclTypeAbbrCodes[AllowFeatureSuppressionDeclAttrLayout::Code];

SmallVector<IdentifierID> ids;
for (auto id : theAttr->getSuppressedFeatures())
ids.push_back(S.addUniquedStringRef(id.str()));

AllowFeatureSuppressionDeclAttrLayout::emitRecord(
S.Out, S.ScratchRecord, abbrCode, theAttr->isImplicit(), ids);
return;
}

case DeclAttrKind::SPIAccessControl: {
auto theAttr = cast<SPIAccessControlAttr>(DA);
auto abbrCode = S.DeclTypeAbbrCodes[SPIAccessControlDeclAttrLayout::Code];
Expand Down
13 changes: 11 additions & 2 deletions test/ModuleInterface/retroactive-conformances.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s
// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface)
// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name Test
// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name Test
// RUN: %FileCheck %s < %t.swiftinterface

// CHECK: #if compiler(>=5.3) && $RetroactiveAttribute
Expand All @@ -20,3 +20,12 @@
extension Int: @retroactive Identifiable {
public var id: Int { self }
}

// CHECK: #if compiler(>=5.3) && $RetroactiveAttribute
// CHECK: extension Swift.String : @retroactive Swift.Identifiable {
// CHECK-NOT: #else
// CHECK: #endif
@_disallowFeatureSuppression(RetroactiveAttribute)
extension String: @retroactive Identifiable {
public var id: String { self }
}