Skip to content

Commit 828813c

Browse files
authored
Merge pull request #85036 from artemcm/AddSupportForWarnAttr
Add support for a declaration attribute `@warn` for source-level warning group behavior control
2 parents bee1ed3 + 0a4d352 commit 828813c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1062
-221
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,15 @@
2727
#include "swift/AST/LayoutConstraintKind.h"
2828
#include "swift/AST/PlatformKind.h"
2929
#include "swift/Basic/BasicBridging.h"
30+
#include "swift/Basic/WarningGroupBehavior.h"
3031

3132
#ifdef NOT_COMPILED_WITH_SWIFT_PURE_BRIDGING_MODE
3233
#include "swift/AST/Attr.h"
3334
#include "swift/AST/Decl.h"
3435
#endif
3536

37+
#include <utility>
38+
3639
SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
3740

3841
namespace llvm {
@@ -1151,11 +1154,36 @@ BridgedSwiftNativeObjCRuntimeBaseAttr_createParsed(BridgedASTContext cContext,
11511154
swift::SourceRange range,
11521155
swift::Identifier name);
11531156

1157+
SWIFT_NAME("BridgedWarnAttr.createParsed(_:atLoc:range:diagGroupName:behavior:reason:)")
1158+
BridgedWarnAttr
1159+
BridgedWarnAttr_createParsed(BridgedASTContext cContext,
1160+
swift::SourceLoc atLoc,
1161+
swift::SourceRange range,
1162+
swift::Identifier diagGroupName,
1163+
swift::WarningGroupBehavior behavior,
1164+
BridgedStringRef reason);
1165+
11541166
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedNonSendableKind {
11551167
BridgedNonSendableKindSpecific,
11561168
BridgedNonSendableKindAssumed,
11571169
};
11581170

1171+
SWIFT_NAME("BridgedWarningGroupBehaviorRule.getGroupName(self:)")
1172+
BridgedStringRef BridgedWarningGroupBehaviorRule_getGroupName(BridgedWarningGroupBehaviorRule rule);
1173+
1174+
SWIFT_NAME("BridgedWarningGroupBehaviorRule.getBehavior(self:)")
1175+
swift::WarningGroupBehavior
1176+
BridgedWarningGroupBehaviorRule_getBehavior(BridgedWarningGroupBehaviorRule rule);
1177+
1178+
1179+
SWIFT_NAME("getDiagnosticGroupLinksCount()")
1180+
SwiftInt
1181+
BridgedDiagnosticGroupLinks_getCount();
1182+
1183+
SWIFT_NAME("getDiagnosticGroupLink(at:)")
1184+
std::pair<BridgedStringRef, BridgedStringRef>
1185+
BridgedDiagnosticGroupLinks_getLink(SwiftInt index);
1186+
11591187
SWIFT_NAME("BridgedNonSendableAttr.createParsed(_:atLoc:range:kind:)")
11601188
BridgedNonSendableAttr BridgedNonSendableAttr_createParsed(
11611189
BridgedASTContext cContext, swift::SourceLoc atLoc,

include/swift/AST/ASTBridgingWrappers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ AST_BRIDGING_WRAPPER_NONNULL(CustomAttribute)
116116
AST_BRIDGING_WRAPPER_NULLABLE(ArgumentList)
117117
AST_BRIDGING_WRAPPER_NULLABLE(AvailabilitySpec)
118118
AST_BRIDGING_WRAPPER_CONST_NONNULL(AvailabilityMacroMap)
119+
AST_BRIDGING_WRAPPER_NULLABLE(WarningGroupBehaviorRule)
119120
AST_BRIDGING_WRAPPER_NONNULL(PoundAvailableInfo)
120121
AST_BRIDGING_WRAPPER_NONNULL(LifetimeEntry)
121122

include/swift/AST/Attr.h

Lines changed: 34 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"
@@ -42,6 +43,7 @@
4243
#include "swift/Basic/SourceLoc.h"
4344
#include "swift/Basic/UUID.h"
4445
#include "swift/Basic/Version.h"
46+
#include "swift/Basic/WarningGroupBehavior.h"
4547
#include "llvm/ADT/DenseMapInfo.h"
4648
#include "llvm/ADT/SmallVector.h"
4749
#include "llvm/ADT/StringRef.h"
@@ -3678,6 +3680,38 @@ class NonexhaustiveAttr : public DeclAttribute {
36783680
}
36793681
};
36803682

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

36823716
/// The kind of unary operator, if any.
36833717
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/DiagnosticEngine.h

Lines changed: 63 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
#include "swift/AST/DeclNameLoc.h"
2222
#include "swift/AST/DiagnosticArgument.h"
2323
#include "swift/AST/DiagnosticConsumer.h"
24+
#include "swift/AST/DiagnosticGroups.h"
2425
#include "swift/AST/TypeLoc.h"
2526
#include "swift/Basic/PrintDiagnosticNamesMode.h"
2627
#include "swift/Basic/Statistic.h"
2728
#include "swift/Basic/Version.h"
28-
#include "swift/Basic/WarningAsErrorRule.h"
29+
#include "swift/Basic/WarningGroupBehaviorRule.h"
2930
#include "swift/Localization/LocalizationFormat.h"
3031
#include "llvm/ADT/BitVector.h"
32+
#include "llvm/ADT/MapVector.h"
3133
#include "llvm/ADT/StringRef.h"
3234
#include "llvm/ADT/StringSet.h"
3335
#include "llvm/Support/Allocator.h"
@@ -612,6 +614,10 @@ namespace swift {
612614
ArrayRef<DiagnosticArgument> Args);
613615
};
614616

617+
618+
using WarningGroupBehaviorMap =
619+
llvm::MapVector<swift::DiagGroupID, WarningGroupBehaviorRule>;
620+
615621
/// Class to track, map, and remap diagnostic severity and fatality
616622
///
617623
class DiagnosticState {
@@ -628,13 +634,13 @@ namespace swift {
628634
/// Don't emit any remarks
629635
bool suppressRemarks = false;
630636

631-
/// A mapping from `DiagGroupID` identifiers to Boolean values indicating
632-
/// whether warnings belonging to the respective diagnostic groups should be
633-
/// escalated to errors.
634-
llvm::BitVector warningsAsErrors;
635-
636-
/// Track which diagnostic group (`DiagGroupID`) warnings should be ignored.
637-
llvm::BitVector ignoredDiagnosticGroups;
637+
/// A mapping from `DiagGroupID` identifiers to `WarningGroupBehaviorRule`
638+
/// values indicating how warnings belonging to the respective diagnostic groups
639+
/// should be emitted. While there is duplication between this data structure
640+
/// being a map keyed with `DiagGroupID` and containing a rule object which also
641+
/// contains a matching `DiagGroupID`, this significantly simplifies bridging
642+
/// values of this map to Swift clients.
643+
WarningGroupBehaviorMap warningGroupBehaviorMap;
638644

639645
/// For compiler-internal purposes only, track which diagnostics should
640646
/// be ignored completely. For example, this is used by LLDB to
@@ -657,7 +663,8 @@ namespace swift {
657663

658664
/// Figure out the Behavior for the given diagnostic, taking current
659665
/// state such as fatality into account.
660-
DiagnosticBehavior determineBehavior(const Diagnostic &diag) const;
666+
DiagnosticBehavior determineBehavior(const Diagnostic &diag,
667+
SourceManager &sourceMgr) const;
661668

662669
/// Updates the diagnostic state for a diagnostic to emit.
663670
void updateFor(DiagnosticBehavior behavior);
@@ -684,45 +691,37 @@ namespace swift {
684691
void setSuppressRemarks(bool val) { suppressRemarks = val; }
685692
bool getSuppressRemarks() const { return suppressRemarks; }
686693

687-
/// Sets whether warnings belonging to the diagnostic group identified by
688-
/// `id` should be escalated to errors.
689-
void setWarningsAsErrorsForDiagGroupID(DiagGroupID id, bool value) {
690-
warningsAsErrors[(unsigned)id] = value;
694+
/// Configure the command-line warning group handling
695+
/// rules (`-Werrr`,`-Wwarning`,`-warnings-as-errors`)
696+
void setWarningGroupControlRules(
697+
const llvm::SmallVector<WarningGroupBehaviorRule, 4> &rules);
698+
699+
/// Add an individual command-line warning group behavior
700+
void addWarningGroupControl(const DiagGroupID &groupID,
701+
WarningGroupBehavior behavior) {
702+
warningGroupBehaviorMap.insert_or_assign(
703+
groupID, WarningGroupBehaviorRule(behavior, groupID));
691704
}
692705

693-
/// Returns a Boolean value indicating whether warnings belonging to the
694-
/// diagnostic group identified by `id` should be escalated to errors.
695-
bool getWarningsAsErrorsForDiagGroupID(DiagGroupID id) const {
696-
return warningsAsErrors[(unsigned)id];
706+
const WarningGroupBehaviorMap&
707+
getWarningGroupBehaviorControlMap() const {
708+
return warningGroupBehaviorMap;
697709
}
698710

699-
/// Whether all warnings should be upgraded to errors or not.
700-
void setAllWarningsAsErrors(bool value) {
701-
// This works as intended because every diagnostic belongs to either a
702-
// custom group or the top-level `DiagGroupID::no_group`, which is also
703-
// a group.
704-
if (value) {
705-
warningsAsErrors.set();
706-
} else {
707-
warningsAsErrors.reset();
708-
}
711+
const std::vector<const WarningGroupBehaviorRule*>
712+
getWarningGroupBehaviorControlRefArray() const {
713+
std::vector<const WarningGroupBehaviorRule*> ruleRefArray;
714+
ruleRefArray.reserve(warningGroupBehaviorMap.size());
715+
for (const auto &rule: warningGroupBehaviorMap)
716+
ruleRefArray.push_back(&rule.second);
717+
return ruleRefArray;
709718
}
710719

711720
void resetHadAnyError() {
712721
anyErrorOccurred = false;
713722
fatalErrorOccurred = false;
714723
}
715724

716-
/// Set whether a diagnostic group should be ignored.
717-
void setIgnoredDiagnosticGroup(DiagGroupID id, bool ignored) {
718-
ignoredDiagnosticGroups[(unsigned)id] = ignored;
719-
}
720-
721-
/// Query whether a specific diagnostic group is ignored.
722-
bool isIgnoredDiagnosticGroup(DiagGroupID id) const {
723-
return ignoredDiagnosticGroups[(unsigned)id];
724-
}
725-
726725
/// Set a specific diagnostic to be ignored by the compiler.
727726
void compilerInternalIgnoreDiagnostic(DiagID id) {
728727
compilerIgnoredDiagnostics[(unsigned)id] = true;
@@ -738,11 +737,10 @@ namespace swift {
738737
std::swap(suppressWarnings, other.suppressWarnings);
739738
std::swap(suppressNotes, other.suppressNotes);
740739
std::swap(suppressRemarks, other.suppressRemarks);
741-
std::swap(warningsAsErrors, other.warningsAsErrors);
740+
std::swap(warningGroupBehaviorMap, other.warningGroupBehaviorMap);
742741
std::swap(fatalErrorOccurred, other.fatalErrorOccurred);
743742
std::swap(anyErrorOccurred, other.anyErrorOccurred);
744743
std::swap(previousBehavior, other.previousBehavior);
745-
std::swap(ignoredDiagnosticGroups, other.ignoredDiagnosticGroups);
746744
}
747745

748746
private:
@@ -752,6 +750,13 @@ namespace swift {
752750

753751
DiagnosticState(DiagnosticState &&) = default;
754752
DiagnosticState &operator=(DiagnosticState &&) = default;
753+
754+
/// If this diagnostic is a warning belonging to a diagnostic group,
755+
/// figure out if there is a source-level (`@warn`) control for this group
756+
/// for this diagnostic's source location.
757+
std::optional<DiagnosticBehavior>
758+
determineUserControlledWarningBehavior(const Diagnostic &diag,
759+
SourceManager &sourceMgr) const;
755760
};
756761

757762
/// A lightweight reference to a diagnostic that's been fully applied to
@@ -951,7 +956,20 @@ namespace swift {
951956
/// Rules are applied in order they appear in the vector.
952957
/// In case the vector contains rules affecting the same diagnostic ID
953958
/// the last rule wins.
954-
void setWarningsAsErrorsRules(const std::vector<WarningAsErrorRule> &rules);
959+
void setWarningGroupControlRules(
960+
const llvm::SmallVector<WarningGroupBehaviorRule, 4> &rules) {
961+
state.setWarningGroupControlRules(rules);
962+
}
963+
964+
const WarningGroupBehaviorMap&
965+
getWarningGroupBehaviorControlMap() const {
966+
return state.getWarningGroupBehaviorControlMap();
967+
}
968+
969+
const std::vector<const WarningGroupBehaviorRule*>
970+
getWarningGroupBehaviorControlRefArray() const {
971+
return state.getWarningGroupBehaviorControlRefArray();
972+
}
955973

956974
/// Whether to print diagnostic names after their messages
957975
void setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode val) {
@@ -982,13 +1000,9 @@ namespace swift {
9821000
localization = diag::LocalizationProducer::producerFor(locale, path);
9831001
}
9841002

985-
bool isIgnoredDiagnosticGroup(DiagGroupID id) const {
986-
return state.isIgnoredDiagnosticGroup(id);
987-
}
988-
989-
bool isIgnoredDiagnosticGroupTree(DiagGroupID id) const {
990-
return state.isIgnoredDiagnosticGroupTree(id);
991-
}
1003+
/// Whether the specified SourceFile enables a given diagnostic group
1004+
/// either syntactically, or via command-line flags.
1005+
bool isDiagnosticGroupEnabled(SourceFile *sf, DiagGroupID groupID) const;
9921006

9931007
void ignoreDiagnostic(DiagID id) {
9941008
state.compilerInternalIgnoreDiagnostic(id);
@@ -1366,7 +1380,8 @@ namespace swift {
13661380
Engine.TentativeDiagnostics.end());
13671381

13681382
for (auto &diagnostic : diagnostics) {
1369-
auto behavior = Engine.state.determineBehavior(diagnostic.Diag);
1383+
auto behavior = Engine.state.determineBehavior(diagnostic.Diag,
1384+
Engine.SourceMgr);
13701385
if (behavior == DiagnosticBehavior::Fatal ||
13711386
behavior == DiagnosticBehavior::Error)
13721387
return true;

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/DiagnosticOptions.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#define SWIFT_BASIC_DIAGNOSTICOPTIONS_H
1515

1616
#include "swift/Basic/PrintDiagnosticNamesMode.h"
17-
#include "swift/Basic/WarningAsErrorRule.h"
17+
#include "swift/Basic/WarningGroupBehaviorRule.h"
1818
#include "llvm/ADT/Hashing.h"
1919
#include <vector>
2020

@@ -76,7 +76,7 @@ class DiagnosticOptions {
7676
bool SuppressRemarks = false;
7777

7878
/// Rules for escalating warnings to errors
79-
std::vector<WarningAsErrorRule> WarningsAsErrorsRules;
79+
llvm::SmallVector<WarningGroupBehaviorRule, 4> WarningGroupControlRules;
8080

8181
/// When printing diagnostics, include either the diagnostic name
8282
/// (diag::whatever) at the end or the associated diagnostic group.

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

include/swift/Basic/SourceManager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,9 @@ class SourceManager {
381381
/// Record the source file as having the given buffer ID.
382382
void recordSourceFile(unsigned bufferID, SourceFile *sourceFile);
383383

384+
/// Remove the source file for the given buffer ID from records.
385+
void deleteSourceFile(unsigned bufferID);
386+
384387
/// Retrieve the source files for the given buffer ID.
385388
llvm::TinyPtrVector<SourceFile *>
386389
getSourceFilesForBufferID(unsigned bufferID) const;

0 commit comments

Comments
 (0)