Skip to content

Commit e593fd9

Browse files
committed
Add parsing for a declaration attribute '@warn' for source-level warning group behavior control
1 parent a4ae171 commit e593fd9

File tree

18 files changed

+382
-2
lines changed

18 files changed

+382
-2
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,21 @@ BridgedSwiftNativeObjCRuntimeBaseAttr_createParsed(BridgedASTContext cContext,
11511151
swift::SourceRange range,
11521152
swift::Identifier name);
11531153

1154+
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedWarningGroupBehavior {
1155+
WarningGroupBehaviorError,
1156+
WarningGroupBehaviorWarning,
1157+
WarningGroupBehaviorIgnored,
1158+
};
1159+
1160+
SWIFT_NAME("BridgedWarnAttr.createParsed(_:atLoc:range:diagGroupName:behavior:reason:)")
1161+
BridgedWarnAttr
1162+
BridgedWarnAttr_createParsed(BridgedASTContext cContext,
1163+
swift::SourceLoc atLoc,
1164+
swift::SourceRange range,
1165+
swift::Identifier diagGroupName,
1166+
BridgedWarningGroupBehavior behavior,
1167+
BridgedStringRef reason);
1168+
11541169
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedNonSendableKind {
11551170
BridgedNonSendableKindSpecific,
11561171
BridgedNonSendableKindAssumed,

include/swift/AST/Attr.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/AST/AvailabilityRange.h"
2424
#include "swift/AST/ConcreteDeclRef.h"
2525
#include "swift/AST/DeclNameLoc.h"
26+
#include "swift/AST/DiagnosticGroups.h"
2627
#include "swift/AST/ExportKind.h"
2728
#include "swift/AST/Identifier.h"
2829
#include "swift/AST/KnownProtocols.h"
@@ -3678,6 +3679,40 @@ class NonexhaustiveAttr : public DeclAttribute {
36783679
}
36793680
};
36803681

3682+
class WarnAttr : public DeclAttribute {
3683+
public:
3684+
enum class Behavior : uint8_t { Error, Warning, Ignored };
3685+
3686+
WarnAttr(DiagGroupID DiagnosticGroupID, Behavior Behavior,
3687+
std::optional<StringRef> Reason, SourceLoc AtLoc, SourceRange Range,
3688+
bool Implicit)
3689+
: DeclAttribute(DeclAttrKind::Warn, AtLoc, Range, Implicit),
3690+
DiagnosticBehavior(Behavior), DiagnosticGroupID(DiagnosticGroupID),
3691+
Reason(Reason) {}
3692+
3693+
WarnAttr(DiagGroupID DiagnosticGroupID, Behavior Behavior, bool Implicit)
3694+
: WarnAttr(DiagnosticGroupID, Behavior, std::nullopt, SourceLoc(),
3695+
SourceRange(), Implicit) {}
3696+
3697+
Behavior DiagnosticBehavior;
3698+
DiagGroupID DiagnosticGroupID;
3699+
const std::optional<StringRef> Reason;
3700+
3701+
static bool classof(const DeclAttribute *DA) {
3702+
return DA->getKind() == DeclAttrKind::Warn;
3703+
}
3704+
3705+
WarnAttr *clone(ASTContext &ctx) const {
3706+
return new (ctx) WarnAttr(DiagnosticGroupID, DiagnosticBehavior, Reason,
3707+
AtLoc, Range, isImplicit());
3708+
}
3709+
3710+
bool isEquivalent(const WarnAttr *other,
3711+
Decl *attachedTo) const {
3712+
return Reason == other->Reason;
3713+
}
3714+
};
3715+
36813716

36823717
/// The kind of unary operator, if any.
36833718
enum class UnaryOperatorKind : uint8_t { None, Prefix, Postfix };

include/swift/AST/DeclAttr.def

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -905,12 +905,18 @@ DECL_ATTR(specialized, Specialized,
905905
AllowMultipleAttributes | LongAttribute | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
906906
172)
907907

908+
908909
SIMPLE_DECL_ATTR(_unsafeSelfDependentResult, UnsafeSelfDependentResult,
909910
OnAccessor,
910911
UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIBreakingToRemove | EquivalentInABIAttr,
911912
173)
912913

913-
LAST_DECL_ATTR(UnsafeSelfDependentResult)
914+
DECL_ATTR(warn, Warn,
915+
OnFunc | OnConstructor | OnDestructor | OnSubscript | OnVar | OnNominalType | OnExtension | OnAccessor | OnImport,
916+
AllowMultipleAttributes | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
917+
174)
918+
919+
LAST_DECL_ATTR(Warn)
914920

915921
#undef DECL_ATTR_ALIAS
916922
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/DiagnosticsParse.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,6 +1768,13 @@ WARNING(attr_warn_unused_result_removed,none,
17681768
"'warn_unused_result' attribute behavior is now the default", ())
17691769
ERROR(attr_warn_unused_result_expected_rparen,none,
17701770
"expected ')' after 'warn_unused_result' attribute", ())
1771+
1772+
// warn
1773+
WARNING(attr_warn_unknown_diagnostic_group_identifier,none,
1774+
"the diagnostic group identifier '%0' is unknown", (StringRef))
1775+
1776+
ERROR(attr_warn_expected_known_behavior,none,
1777+
"expected diagnostic behavior argument '%0' to be either 'error', 'warning' or 'ignored'", (StringRef))
17711778

17721779
// _specialize
17731780
ERROR(attr_specialize_missing_colon,none,

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,9 @@ EXPERIMENTAL_FEATURE(CheckImplementationOnlyStrict, false)
573573
/// Check that use sites have the required @_spi import for operators.
574574
EXPERIMENTAL_FEATURE(EnforceSPIOperatorGroup, true)
575575

576+
/// Enable source-level warning control with `@warn`
577+
EXPERIMENTAL_FEATURE(SourceWarningControl, true)
578+
576579
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
577580
#undef EXPERIMENTAL_FEATURE
578581
#undef UPCOMING_FEATURE

lib/AST/ASTDumper.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5610,6 +5610,30 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
56105610
}
56115611
printFoot();
56125612
}
5613+
5614+
void visitWarnAttr(WarnAttr *Attr, Label label) {
5615+
printCommon(Attr, "warn", label);
5616+
auto &diagGroupInfo = getDiagGroupInfoByID(Attr->DiagnosticGroupID);
5617+
printFieldRaw([&](raw_ostream &out) { out << diagGroupInfo.name; },
5618+
Label::always("diagGroupID:"));
5619+
switch (Attr->DiagnosticBehavior) {
5620+
case WarnAttr::Behavior::Error:
5621+
printFieldRaw([&](raw_ostream &out) { out << "error"; },
5622+
Label::always("as:"));
5623+
break;
5624+
case WarnAttr::Behavior::Warning:
5625+
printFieldRaw([&](raw_ostream &out) { out << "warning"; },
5626+
Label::always("as:"));
5627+
break;
5628+
case WarnAttr::Behavior::Ignored:
5629+
printFieldRaw([&](raw_ostream &out) { out << "ignored"; },
5630+
Label::always("as:"));
5631+
break;
5632+
}
5633+
if (Attr->Reason)
5634+
printFieldQuoted(Attr->Reason, Label::always("reason:"));
5635+
printFoot();
5636+
}
56135637
};
56145638

56155639
} // end anonymous namespace

lib/AST/Attr.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,31 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
13261326
Printer.printAttrName("@section");
13271327
Printer << "(\"" << cast<SectionAttr>(this)->Name << "\")";
13281328
break;
1329+
1330+
case DeclAttrKind::Warn: {
1331+
auto warnAttr = cast<WarnAttr>(this);
1332+
Printer.printAttrName("@warn(");
1333+
1334+
auto &diagGroupInfo = getDiagGroupInfoByID(warnAttr->DiagnosticGroupID);
1335+
Printer.printText(diagGroupInfo.name);
1336+
Printer << ", ";
1337+
switch (cast<WarnAttr>(this)->DiagnosticBehavior) {
1338+
case WarnAttr::Behavior::Error:
1339+
Printer << "as: error";
1340+
break;
1341+
case WarnAttr::Behavior::Warning:
1342+
Printer << "as: warning";
1343+
break;
1344+
case WarnAttr::Behavior::Ignored:
1345+
Printer << "as: ignored";
1346+
break;
1347+
}
1348+
if (cast<WarnAttr>(this)->Reason) {
1349+
Printer << ", \"" << *(cast<WarnAttr>(this)->Reason) << "\"";
1350+
}
1351+
Printer <<")";
1352+
}
1353+
break;
13291354

13301355
case DeclAttrKind::ObjC: {
13311356
Printer.printAttrName("@objc");
@@ -2017,6 +2042,8 @@ StringRef DeclAttribute::getAttrName() const {
20172042
return "_rawLayout";
20182043
case DeclAttrKind::Extern:
20192044
return "_extern";
2045+
case DeclAttrKind::Warn:
2046+
return "warn";
20202047
case DeclAttrKind::AllowFeatureSuppression:
20212048
if (cast<AllowFeatureSuppressionAttr>(this)->getInverted()) {
20222049
return "_disallowFeatureSuppression";

lib/AST/Bridging/DeclAttributeBridging.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,38 @@ BridgedSwiftNativeObjCRuntimeBaseAttr_createParsed(BridgedASTContext cContext,
500500
SwiftNativeObjCRuntimeBaseAttr(name, atLoc, range, /*Implicit=*/false);
501501
}
502502

503+
BridgedWarnAttr
504+
BridgedWarnAttr_createParsed(BridgedASTContext cContext,
505+
SourceLoc atLoc,
506+
SourceRange range,
507+
Identifier diagGroupName,
508+
BridgedWarningGroupBehavior behavior,
509+
BridgedStringRef reason) {
510+
ASTContext &context = cContext.unbridged();
511+
auto diagGroupID = getDiagGroupIDByName(diagGroupName.str());
512+
513+
WarnAttr::Behavior attrBehavior;
514+
switch (behavior) {
515+
case WarningGroupBehaviorError:
516+
attrBehavior = WarnAttr::Behavior::Error;
517+
break;
518+
case WarningGroupBehaviorWarning:
519+
attrBehavior = WarnAttr::Behavior::Warning;
520+
break;
521+
case WarningGroupBehaviorIgnored:
522+
attrBehavior = WarnAttr::Behavior::Ignored;
523+
break;
524+
}
525+
526+
std::optional<StringRef> reasonText = std::nullopt;
527+
if (!reason.getIsEmpty())
528+
reasonText = reason.unbridged();
529+
530+
return new (context) WarnAttr(*diagGroupID, attrBehavior,
531+
reasonText, atLoc, range,
532+
/*Implicit=*/false);
533+
}
534+
503535
static NonSendableKind unbridged(BridgedNonSendableKind kind) {
504536
switch (kind) {
505537
case BridgedNonSendableKindSpecific:

lib/AST/FeatureSet.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,10 @@ static bool usesFeatureConcurrencySyntaxSugar(Decl *decl) {
337337
return false;
338338
}
339339

340+
static bool usesFeatureSourceWarningControl(Decl *decl) {
341+
return decl->getAttrs().hasAttribute<WarnAttr>();
342+
}
343+
340344
static bool usesFeatureCompileTimeValues(Decl *decl) {
341345
return decl->getAttrs().hasAttribute<ConstValAttr>() ||
342346
decl->getAttrs().hasAttribute<ConstInitializedAttr>();

lib/ASTGen/Sources/ASTGen/DeclAttrs.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ extension ASTGenVisitor {
198198
return handle(self.generateStorageRestrictionAttr(attribute: node)?.asDeclAttribute)
199199
case .SwiftNativeObjCRuntimeBase:
200200
return handle(self.generateSwiftNativeObjCRuntimeBaseAttr(attribute: node)?.asDeclAttribute)
201+
case .Warn:
202+
return handle(self.generateWarnAttr(attribute: node)?.asDeclAttribute)
201203
case .Transpose:
202204
return handle(self.generateTransposeAttr(attribute: node)?.asDeclAttribute)
203205
case .TypeEraser:
@@ -2198,6 +2200,56 @@ extension ASTGenVisitor {
21982200
name: name
21992201
)
22002202
}
2203+
2204+
/// E.g.:
2205+
/// ```
2206+
/// @warn(DiagGroupID, as: Behavior, reason: String?)
2207+
/// ```
2208+
func generateWarnAttr(attribute node: AttributeSyntax) -> BridgedWarnAttr? {
2209+
guard let diagGroupIdentifier: swift.Identifier = self.generateWithLabeledExprListArguments(attribute: node, { args in
2210+
self.generateConsumingAttrOption(args: &args, label: nil) { expr in
2211+
guard let declRefExpr = expr.as(DeclReferenceExprSyntax.self) else {
2212+
return nil
2213+
}
2214+
return self.generateIdentifier(declRefExpr.baseName)
2215+
}
2216+
}) else {
2217+
return nil
2218+
}
2219+
2220+
guard let behavior: BridgedWarningGroupBehavior = self.generateWithLabeledExprListArguments(attribute: node, { args in
2221+
self.generateConsumingAttrOption(args: &args, label: "as") { expr in
2222+
guard let declRefExpr = expr.as(DeclReferenceExprSyntax.self) else {
2223+
return nil
2224+
}
2225+
switch declRefExpr.baseName.text {
2226+
case "error": return BridgedWarningGroupBehavior.WarningGroupBehaviorError
2227+
case "warning": return BridgedWarningGroupBehavior.WarningGroupBehaviorWarning
2228+
case "ignored": return BridgedWarningGroupBehavior.WarningGroupBehaviorIgnored
2229+
default: return nil
2230+
}
2231+
}
2232+
}) else {
2233+
return nil
2234+
}
2235+
2236+
let reason: BridgedStringRef
2237+
if let userSpecifiedReason = self.generateWithLabeledExprListArguments(attribute: node, { args in
2238+
self.generateConsumingSimpleStringLiteralAttrOption(args: &args, label: "reason")}) {
2239+
reason = userSpecifiedReason
2240+
} else {
2241+
reason = allocateBridgedString("")
2242+
}
2243+
2244+
return .createParsed(
2245+
self.ctx,
2246+
atLoc: self.generateSourceLoc(node.atSign),
2247+
range: self.generateAttrSourceRange(node),
2248+
diagGroupName: diagGroupIdentifier,
2249+
behavior: behavior,
2250+
reason: reason
2251+
)
2252+
}
22012253

22022254
/// E.g.:
22032255
/// ```

0 commit comments

Comments
 (0)