Skip to content

Commit f166258

Browse files
committed
Implement support for unified warning group behavior queries per-diagnostic
Unified across module-wide configuration flags (`-Wwarning`, `-Werror`, etc.) and syntactic configuration attribute `@warn`.
1 parent 8a86e7f commit f166258

31 files changed

+561
-241
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,15 @@
2626
#include "swift/AST/LayoutConstraintKind.h"
2727
#include "swift/AST/PlatformKind.h"
2828
#include "swift/Basic/BasicBridging.h"
29+
#include "swift/Basic/WarningGroupBehavior.h"
2930

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

36+
#include <utility>
37+
3538
SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
3639

3740
namespace llvm {
@@ -1100,26 +1103,36 @@ BridgedSwiftNativeObjCRuntimeBaseAttr_createParsed(BridgedASTContext cContext,
11001103
swift::SourceRange range,
11011104
swift::Identifier name);
11021105

1103-
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedWarningGroupBehavior {
1104-
WarningGroupBehaviorError,
1105-
WarningGroupBehaviorWarning,
1106-
WarningGroupBehaviorIgnored,
1107-
};
1108-
11091106
SWIFT_NAME("BridgedWarnAttr.createParsed(_:atLoc:range:diagGroupName:behavior:reason:)")
11101107
BridgedWarnAttr
11111108
BridgedWarnAttr_createParsed(BridgedASTContext cContext,
11121109
swift::SourceLoc atLoc,
11131110
swift::SourceRange range,
11141111
swift::Identifier diagGroupName,
1115-
BridgedWarningGroupBehavior behavior,
1112+
swift::WarningGroupBehavior behavior,
11161113
BridgedStringRef reason);
11171114

11181115
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedNonSendableKind {
11191116
BridgedNonSendableKindSpecific,
11201117
BridgedNonSendableKindAssumed,
11211118
};
11221119

1120+
SWIFT_NAME("BridgedWarningGroupBehaviorRule.getGroupName(self:)")
1121+
BridgedStringRef BridgedWarningGroupBehaviorRule_getGroupName(BridgedWarningGroupBehaviorRule rule);
1122+
1123+
SWIFT_NAME("BridgedWarningGroupBehaviorRule.getBehavior(self:)")
1124+
swift::WarningGroupBehavior
1125+
BridgedWarningGroupBehaviorRule_getBehavior(BridgedWarningGroupBehaviorRule rule);
1126+
1127+
1128+
SWIFT_NAME("getDiagnosticGroupLinksCount()")
1129+
SwiftInt
1130+
BridgedDiagnosticGroupLinks_getCount();
1131+
1132+
SWIFT_NAME("getDiagnosticGroupLink(at:)")
1133+
std::pair<BridgedStringRef, BridgedStringRef>
1134+
BridgedDiagnosticGroupLinks_getLink(SwiftInt index);
1135+
11231136
SWIFT_NAME("BridgedNonSendableAttr.createParsed(_:atLoc:range:kind:)")
11241137
BridgedNonSendableAttr BridgedNonSendableAttr_createParsed(
11251138
BridgedASTContext cContext, swift::SourceLoc atLoc,

include/swift/AST/ASTBridgingWrappers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ AST_BRIDGING_WRAPPER_NONNULL(CustomAttribute)
114114
AST_BRIDGING_WRAPPER_NULLABLE(ArgumentList)
115115
AST_BRIDGING_WRAPPER_NULLABLE(AvailabilitySpec)
116116
AST_BRIDGING_WRAPPER_CONST_NONNULL(AvailabilityMacroMap)
117+
AST_BRIDGING_WRAPPER_NULLABLE(WarningGroupBehaviorRule)
117118
AST_BRIDGING_WRAPPER_NONNULL(PoundAvailableInfo)
118119
AST_BRIDGING_WRAPPER_NONNULL(LifetimeEntry)
119120

include/swift/AST/ASTContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,10 @@ class ASTContext final {
14831483
/// the language options.
14841484
bool shouldPerformTypoCorrection();
14851485

1486+
/// Whether the specified SourceFile enables a given diagnostic group
1487+
/// either syntactically, or via command-line flags.
1488+
bool isDiagnosticGroupEnabled(SourceFile *sf, DiagGroupID groupID) const;
1489+
14861490
private:
14871491
friend class IntrinsicInfo;
14881492
/// Retrieve an LLVMContext that is used for scratch space for intrinsic lookup.

include/swift/AST/Attr.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "swift/Basic/SourceLoc.h"
4343
#include "swift/Basic/UUID.h"
4444
#include "swift/Basic/Version.h"
45+
#include "swift/Basic/WarningGroupBehavior.h"
4546
#include "llvm/ADT/DenseMapInfo.h"
4647
#include "llvm/ADT/SmallVector.h"
4748
#include "llvm/ADT/StringRef.h"
@@ -3640,20 +3641,18 @@ class NonexhaustiveAttr : public DeclAttribute {
36403641

36413642
class WarnAttr : public DeclAttribute {
36423643
public:
3643-
enum class Behavior : uint8_t { Error, Warning, Ignored };
3644-
3645-
WarnAttr(DiagGroupID DiagnosticGroupID, Behavior Behavior,
3644+
WarnAttr(DiagGroupID DiagnosticGroupID, WarningGroupBehavior Behavior,
36463645
std::optional<StringRef> Reason, SourceLoc AtLoc, SourceRange Range,
36473646
bool Implicit)
36483647
: DeclAttribute(DeclAttrKind::Warn, AtLoc, Range, Implicit),
36493648
DiagnosticBehavior(Behavior), DiagnosticGroupID(DiagnosticGroupID),
36503649
Reason(Reason) {}
36513650

3652-
WarnAttr(DiagGroupID DiagnosticGroupID, Behavior Behavior, bool Implicit)
3651+
WarnAttr(DiagGroupID DiagnosticGroupID, WarningGroupBehavior Behavior, bool Implicit)
36533652
: WarnAttr(DiagnosticGroupID, Behavior, std::nullopt, SourceLoc(),
36543653
SourceRange(), Implicit) {}
36553654

3656-
Behavior DiagnosticBehavior;
3655+
WarningGroupBehavior DiagnosticBehavior;
36573656
DiagGroupID DiagnosticGroupID;
36583657
const std::optional<StringRef> Reason;
36593658

include/swift/AST/DiagnosticEngine.h

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#include "swift/Basic/PrintDiagnosticNamesMode.h"
2626
#include "swift/Basic/Statistic.h"
2727
#include "swift/Basic/Version.h"
28-
#include "swift/Basic/WarningAsErrorRule.h"
28+
#include "swift/Basic/WarningGroupBehaviorRule.h"
2929
#include "swift/Localization/LocalizationFormat.h"
3030
#include "llvm/ADT/BitVector.h"
3131
#include "llvm/ADT/StringRef.h"
@@ -628,13 +628,10 @@ namespace swift {
628628
/// Don't emit any remarks
629629
bool suppressRemarks = false;
630630

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;
631+
/// A mapping from `DiagGroupID` identifiers to `WarningGroupBehavior`
632+
/// values indicating how warnings belonging to the respective diagnostic groups
633+
/// should be emitted.
634+
std::unordered_map<DiagGroupID, WarningGroupBehavior> warningGroupBehaviorMap;
638635

639636
/// For compiler-internal purposes only, track which diagnostics should
640637
/// be ignored completely. For example, this is used by LLDB to
@@ -657,7 +654,15 @@ namespace swift {
657654

658655
/// Figure out the Behavior for the given diagnostic, taking current
659656
/// state such as fatality into account.
660-
DiagnosticBehavior determineBehavior(const Diagnostic &diag) const;
657+
DiagnosticBehavior determineBehavior(const Diagnostic &diag,
658+
SourceManager &sourceMgr) const;
659+
660+
/// If this diagnostic is a warning belonging to a diagnostic group,
661+
/// figure out if there is a source-level (`@warn`) control for this group
662+
/// for this diagnostic's source location.
663+
std::optional<DiagnosticBehavior>
664+
determineUserControlledWarningBehavior(const Diagnostic &diag,
665+
SourceManager &sourceMgr) const;
661666

662667
/// Updates the diagnostic state for a diagnostic to emit.
663668
void updateFor(DiagnosticBehavior behavior);
@@ -684,43 +689,24 @@ namespace swift {
684689
void setSuppressRemarks(bool val) { suppressRemarks = val; }
685690
bool getSuppressRemarks() const { return suppressRemarks; }
686691

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;
691-
}
692-
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];
697-
}
692+
/// Configure the command-line warning group handling
693+
/// rules (`-Werrr`,`-Wwarning`,`-warnings-as-errors`)
694+
void setWarningGroupControlRules(
695+
const llvm::SmallVector<WarningGroupBehaviorRule, 4> &rules);
698696

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-
}
697+
const std::unordered_map<DiagGroupID, WarningGroupBehavior> &
698+
getWarningGroupBehaviorControlMap() const {
699+
return warningGroupBehaviorMap;
709700
}
710701

711702
void resetHadAnyError() {
712703
anyErrorOccurred = false;
713704
fatalErrorOccurred = false;
714705
}
715706

716-
/// Set whether a diagnostic group should be ignored.
717-
void setIgnoredDiagnosticGroup(DiagGroupID id, bool ignored) {
718-
ignoredDiagnosticGroups[(unsigned)id] = ignored;
719-
}
720-
721707
/// Query whether a specific diagnostic group is ignored.
722708
bool isIgnoredDiagnosticGroup(DiagGroupID id) const {
723-
return ignoredDiagnosticGroups[(unsigned)id];
709+
return warningGroupBehaviorMap.at(id) == WarningGroupBehavior::Ignored;
724710
}
725711

726712
/// Set a specific diagnostic to be ignored by the compiler.
@@ -738,11 +724,10 @@ namespace swift {
738724
std::swap(suppressWarnings, other.suppressWarnings);
739725
std::swap(suppressNotes, other.suppressNotes);
740726
std::swap(suppressRemarks, other.suppressRemarks);
741-
std::swap(warningsAsErrors, other.warningsAsErrors);
727+
std::swap(warningGroupBehaviorMap, other.warningGroupBehaviorMap);
742728
std::swap(fatalErrorOccurred, other.fatalErrorOccurred);
743729
std::swap(anyErrorOccurred, other.anyErrorOccurred);
744730
std::swap(previousBehavior, other.previousBehavior);
745-
std::swap(ignoredDiagnosticGroups, other.ignoredDiagnosticGroups);
746731
}
747732

748733
private:
@@ -951,7 +936,15 @@ namespace swift {
951936
/// Rules are applied in order they appear in the vector.
952937
/// In case the vector contains rules affecting the same diagnostic ID
953938
/// the last rule wins.
954-
void setWarningsAsErrorsRules(const std::vector<WarningAsErrorRule> &rules);
939+
void setWarningGroupControlRules(
940+
const llvm::SmallVector<WarningGroupBehaviorRule, 4> &rules) {
941+
state.setWarningGroupControlRules(rules);
942+
}
943+
944+
const std::unordered_map<DiagGroupID, WarningGroupBehavior> &
945+
getWarningGroupBehaviorControlMap() const {
946+
return state.getWarningGroupBehaviorControlMap();
947+
}
955948

956949
/// Whether to print diagnostic names after their messages
957950
void setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode val) {
@@ -1366,7 +1359,8 @@ namespace swift {
13661359
Engine.TentativeDiagnostics.end());
13671360

13681361
for (auto &diagnostic : diagnostics) {
1369-
auto behavior = Engine.state.determineBehavior(diagnostic.Diag);
1362+
auto behavior = Engine.state.determineBehavior(diagnostic.Diag,
1363+
Engine.SourceMgr);
13701364
if (behavior == DiagnosticBehavior::Fatal ||
13711365
behavior == DiagnosticBehavior::Error)
13721366
return true;

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

Lines changed: 0 additions & 75 deletions
This file was deleted.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===-- WarningGroupBehavior.h ----------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_BASIC_WARNINGBEHAVIOR_H
14+
#define SWIFT_BASIC_WARNINGBEHAVIOR_H
15+
16+
/// `WarningGroupBehavior.h` is imported into Swift. Be *very* careful with what you
17+
/// include here and keep these includes minimal!
18+
///
19+
/// See include guidelines and caveats in `BasicBridging.h`.
20+
#include "swift/Basic/SwiftBridging.h"
21+
#include <stdint.h>
22+
#include <utility>
23+
#include <array>
24+
25+
namespace swift {
26+
27+
// Describes how a diagnostic group's warnings are to be emitted
28+
enum ENUM_EXTENSIBILITY_ATTR(closed) WarningGroupBehavior {
29+
AsError SWIFT_NAME("error"),
30+
AsWarning SWIFT_NAME("warning"),
31+
Ignored SWIFT_NAME("ignored"),
32+
None SWIFT_NAME("none")
33+
};
34+
35+
constexpr const auto DiagLinksCount = [] {
36+
size_t count = 0;
37+
#define GROUP_LINK(Parent, Child) ++count;
38+
#include "swift/AST/DiagnosticGroups.def"
39+
return count;
40+
}();
41+
42+
constexpr std::array<std::pair<const char*, const char*>, swift::DiagLinksCount> DiagnosticGroupLinks = {{
43+
#define GROUP_LINK(Parent, Child) {#Parent, #Child},
44+
#include "swift/AST/DiagnosticGroups.def"
45+
}};
46+
47+
} // namespace swift
48+
49+
#endif // SWIFT_BASIC_WARNINGBEHAVIOR_H
50+

0 commit comments

Comments
 (0)