Skip to content

Commit 32d599d

Browse files
committed
[Diagnostics] Add -[no-]warning-as-error flags for precise control over warning behavior
This commit adds new compiler options -no-warning-as-error/-warning-as-error which allows users to specify behavior for exact warnings and warning groups.
1 parent 7eff8fb commit 32d599d

37 files changed

+820
-116
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ struct BridgedPatternBindingEntry {
309309
// NOTE: This must be the same underlying value as C++ 'swift::DiagID' defined
310310
// in 'DiagnosticList.cpp'.
311311
enum ENUM_EXTENSIBILITY_ATTR(open) BridgedDiagID : uint32_t {
312-
#define DIAG(KIND, ID, Options, Text, Signature) BridgedDiagID_##ID,
312+
#define DIAG(KIND, ID, Group, Options, Text, Signature) BridgedDiagID_##ID,
313313
#include "swift/AST/DiagnosticsAll.def"
314314
};
315315

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===--- DefineDiagnosticGroupsMacros.def -----------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 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+
// This file defines macros defining diagnostic groups.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
// Define macros
18+
#if defined(DEFINE_DIAGNOSTIC_GROUPS_MACROS) && \
19+
!defined(UNDEFINE_DIAGNOSTIC_GROUPS_MACROS)
20+
21+
#undef DEFINE_DIAGNOSTIC_GROUPS_MACROS
22+
23+
#ifndef GROUP_DECL
24+
#error GROUP_DECL(Name, Version) macro is not defined
25+
#endif
26+
27+
#ifndef GROUP_LINK
28+
#error GROUP_LINK(Parent, Child) macro is not defined
29+
#endif
30+
31+
// FOR_EACH macro implementation from
32+
// https://www.scs.stanford.edu/~dm/blog/va-opt.html
33+
// Extended with "context" parameter to pass an additional common argument
34+
#define PARENS ()
35+
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
36+
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
37+
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
38+
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
39+
#define EXPAND1(...) __VA_ARGS__
40+
#define FOR_EACH_WITH_CTX(macro, context, ...) \
41+
__VA_OPT__(EXPAND(FOR_EACH_WITH_CTX_HELPER(macro, context, __VA_ARGS__)))
42+
#define FOR_EACH_WITH_CTX_HELPER(macro, context, a1, ...) \
43+
macro(context, a1) \
44+
__VA_OPT__(FOR_EACH_WITH_CTX_AGAIN PARENS (macro, context, __VA_ARGS__))
45+
#define FOR_EACH_WITH_CTX_AGAIN() FOR_EACH_WITH_CTX_HELPER
46+
47+
// GROUP macro:
48+
// Name - group name as it appears in DiagGroupID enum and DiagGroupInfo.name
49+
// Version - compiler version when this group was added
50+
// __VA_ARGS__ - subgroups of this group
51+
#define GROUP(Name, Version, ...) \
52+
GROUP_DECL(Name, Version) \
53+
FOR_EACH_WITH_CTX(GROUP_LINK, Name, __VA_ARGS__)
54+
55+
// Undefine macros
56+
#elif defined(UNDEFINE_DIAGNOSTIC_GROUPS_MACROS) && \
57+
!defined(DEFINE_DIAGNOSTIC_GROUPS_MACROS)
58+
59+
#undef UNDEFINE_DIAGNOSTIC_GROUPS_MACROS
60+
61+
#ifndef GROUP
62+
#error Trying to undefine the diagnostic groups macros, but GROUP macro wasn't defined
63+
#endif
64+
65+
#undef PARENS
66+
#undef EXPAND
67+
#undef EXPAND4
68+
#undef EXPAND3
69+
#undef EXPAND2
70+
#undef EXPAND1
71+
#undef FOR_EACH
72+
#undef FOR_EACH_HELPER
73+
#undef FOR_EACH_AGAIN
74+
#undef GROUP
75+
#undef GROUP_DECL
76+
#undef GROUP_LINK
77+
78+
#else
79+
#error Invalid DefineDiagnosticGroupsMacros.h inclusion
80+
#endif

include/swift/AST/DefineDiagnosticMacros.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,39 @@
1717
// Define macros
1818
#ifdef DEFINE_DIAGNOSTIC_MACROS
1919

20-
#if !(defined(DIAG) || (defined(ERROR) && defined(WARNING) && defined(NOTE) && \
21-
defined(REMARK)))
22-
#error Must define either DIAG or the set {ERROR,WARNING,NOTE,REMARK}
20+
#if !(defined(DIAG) || (defined(GROUPED_ERROR) && defined(GROUPED_WARNING) && \
21+
defined(NOTE) && defined(REMARK)))
22+
#error Must define either DIAG or the set {GROUPED_ERROR,GROUPED_WARNING,NOTE,REMARK}
23+
#endif
24+
25+
#ifndef GROUPED_ERROR
26+
#define GROUPED_ERROR(ID, Group, Options, Text, Signature) \
27+
DIAG(ERROR, ID, Group, Options, Text, Signature)
2328
#endif
2429

2530
#ifndef ERROR
2631
#define ERROR(ID, Options, Text, Signature) \
27-
DIAG(ERROR, ID, Options, Text, Signature)
32+
GROUPED_ERROR(ID, no_group, Options, Text, Signature)
33+
#endif
34+
35+
#ifndef GROUPED_WARNING
36+
#define GROUPED_WARNING(ID, Group, Options, Text, Signature) \
37+
DIAG(WARNING, ID, Group, Options, Text, Signature)
2838
#endif
2939

3040
#ifndef WARNING
3141
#define WARNING(ID, Options, Text, Signature) \
32-
DIAG(WARNING, ID, Options, Text, Signature)
42+
GROUPED_WARNING(ID, no_group, Options, Text, Signature)
3343
#endif
3444

3545
#ifndef NOTE
3646
#define NOTE(ID, Options, Text, Signature) \
37-
DIAG(NOTE, ID, Options, Text, Signature)
47+
DIAG(NOTE, ID, no_group, Options, Text, Signature)
3848
#endif
3949

4050
#ifndef REMARK
4151
#define REMARK(ID, Options, Text, Signature) \
42-
DIAG(REMARK, ID, Options, Text, Signature)
52+
DIAG(REMARK, ID, no_group, Options, Text, Signature)
4353
#endif
4454

4555
#ifndef FIXIT
@@ -61,7 +71,9 @@
6171
#undef REMARK
6272
#undef NOTE
6373
#undef WARNING
74+
#undef GROUPED_WARNING
6475
#undef ERROR
76+
#undef GROUPED_ERROR
6577
#undef FIXIT
6678

6779
#endif

include/swift/AST/DiagnosticEngine.h

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/AST/TypeLoc.h"
2525
#include "swift/Basic/Statistic.h"
2626
#include "swift/Basic/Version.h"
27+
#include "swift/Basic/WarningAsErrorRule.h"
2728
#include "swift/Localization/LocalizationFormat.h"
2829
#include "llvm/ADT/BitVector.h"
2930
#include "llvm/ADT/StringRef.h"
@@ -839,8 +840,8 @@ namespace swift {
839840
/// Don't emit any remarks
840841
bool suppressRemarks = false;
841842

842-
/// Emit all warnings as errors
843-
bool warningsAsErrors = false;
843+
/// Treat these warnings as errors. Indicies here corespond to DiagID enum
844+
llvm::BitVector warningsAsErrors;
844845

845846
/// Whether a fatal error has occurred
846847
bool fatalErrorOccurred = false;
@@ -881,9 +882,22 @@ namespace swift {
881882
void setSuppressRemarks(bool val) { suppressRemarks = val; }
882883
bool getSuppressRemarks() const { return suppressRemarks; }
883884

884-
/// Whether to treat warnings as errors
885-
void setWarningsAsErrors(bool val) { warningsAsErrors = val; }
886-
bool getWarningsAsErrors() const { return warningsAsErrors; }
885+
/// Whether a warning should be upgraded to an error or not
886+
void setWarningAsErrorForDiagID(DiagID id, bool value) {
887+
warningsAsErrors[(unsigned)id] = value;
888+
}
889+
bool getWarningAsErrorForDiagID(DiagID id) {
890+
return warningsAsErrors[(unsigned)id];
891+
}
892+
893+
/// Whether all warnings should be upgraded to errors or not
894+
void setAllWarningsAsErrors(bool value) {
895+
if (value) {
896+
warningsAsErrors.set();
897+
} else {
898+
warningsAsErrors.reset();
899+
}
900+
}
887901

888902
void resetHadAnyError() {
889903
anyErrorOccurred = false;
@@ -1093,11 +1107,15 @@ namespace swift {
10931107
return state.getSuppressRemarks();
10941108
}
10951109

1096-
/// Whether to treat warnings as errors
1097-
void setWarningsAsErrors(bool val) { state.setWarningsAsErrors(val); }
1098-
bool getWarningsAsErrors() const {
1099-
return state.getWarningsAsErrors();
1100-
}
1110+
/// Apply rules specifing what warnings should or shouldn't be treated as
1111+
/// errors. For group rules the string is either a group name defined by
1112+
/// DiagnosticGroups.def or a string with format "_id:<diag_id>" where
1113+
/// <diag_id> is one of the diagnostic IDs listed in
1114+
/// include/swift/AST/Diagnostics*.def
1115+
/// Rules are applied in order they appear in the vector.
1116+
/// In case the vector contains rules affecting the same diagnostic ID
1117+
/// the last rule wins.
1118+
void setWarningsAsErrorsRules(const std::vector<WarningAsErrorRule> &rules);
11011119

11021120
/// Whether to print diagnostic names after their messages
11031121
void setPrintDiagnosticNames(bool val) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===--- DiagnosticGroups.def - Diagnostic Groups ---------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 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+
// This file defines diagnostic groups.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#define DEFINE_DIAGNOSTIC_GROUPS_MACROS
18+
#include "swift/AST/DefineDiagnosticGroupsMacros.h"
19+
20+
#pragma clang diagnostic push
21+
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
22+
23+
GROUP(no_group, 6.0)
24+
25+
GROUP(deprecated, 6.0, availability_deprecated)
26+
GROUP(availability_deprecated, 6.0)
27+
28+
GROUP(unknown_warning_group, 6.0)
29+
GROUP(error_in_future_swift_version, 6.0)
30+
31+
#pragma clang diagnostic pop
32+
33+
#define UNDEFINE_DIAGNOSTIC_GROUPS_MACROS
34+
#include "swift/AST/DefineDiagnosticGroupsMacros.h"

include/swift/AST/DiagnosticGroups.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//===--- DiagnosticGroups.h - Diagnostic Groups -----------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 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+
// This file defines the diagnostic groups enumaration, group graph
14+
// and auxilary functions.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_DIAGNOSTICGROUPS_H
19+
#define SWIFT_DIAGNOSTICGROUPS_H
20+
21+
#include "swift/AST/DiagnosticList.h"
22+
#include "llvm/ADT/ArrayRef.h"
23+
#include <array>
24+
#include <string_view>
25+
#include <unordered_map>
26+
27+
namespace swift {
28+
29+
enum class DiagGroupID : uint16_t {
30+
#define GROUP_DECL(Name, Version) Name,
31+
#define GROUP_LINK(Parent, Child)
32+
#include "swift/AST/DiagnosticGroups.def"
33+
};
34+
35+
constexpr const auto DiagGroupsCount = [] {
36+
size_t count = 0;
37+
#define GROUP_DECL(Name, Version) count++;
38+
#define GROUP_LINK(Parent, Child)
39+
#include "DiagnosticGroups.def"
40+
return count;
41+
}();
42+
43+
struct DiagGroupInfo {
44+
DiagGroupID id;
45+
std::string_view name;
46+
std::string_view version;
47+
llvm::ArrayRef<DiagGroupID> supergroups;
48+
llvm::ArrayRef<DiagGroupID> subgroups;
49+
llvm::ArrayRef<DiagID> diagnostics;
50+
51+
void
52+
traverseDepthFirst(std::function<void(const DiagGroupInfo &)> func) const;
53+
};
54+
55+
extern const std::array<DiagGroupInfo, DiagGroupsCount> diagnosticGroupsInfo;
56+
const DiagGroupInfo &getDiagGroupInfoByID(DiagGroupID id);
57+
std::optional<DiagGroupID> getDiagGroupIDByName(std::string_view name);
58+
59+
} // end namespace swift
60+
61+
#endif /* SWIFT_DIAGNOSTICGROUPS_H */

include/swift/AST/DiagnosticList.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===--- DiagnosticList.h - Diagnostic Definitions --------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 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+
// This file defines all of the diagnostics emitted by Swift.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_DIAGNOSTICLIST_H
18+
#define SWIFT_DIAGNOSTICLIST_H
19+
20+
#include <cstdint>
21+
22+
namespace swift {
23+
24+
/// Enumeration describing all of possible diagnostics.
25+
///
26+
/// Each of the diagnostics described in Diagnostics.def has an entry in
27+
/// this enumeration type that uniquely identifies it.
28+
enum class DiagID : uint32_t {
29+
#define DIAG(KIND, ID, Group, Options, Text, Signature) ID,
30+
#include "swift/AST/DiagnosticsAll.def"
31+
};
32+
static_assert(static_cast<uint32_t>(swift::DiagID::invalid_diagnostic) == 0,
33+
"0 is not the invalid diagnostic ID");
34+
35+
enum class FixItID : uint32_t {
36+
#define DIAG(KIND, ID, Group, Options, Text, Signature)
37+
#define FIXIT(ID, Text, Signature) ID,
38+
#include "swift/AST/DiagnosticsAll.def"
39+
};
40+
41+
} // end namespace swift
42+
43+
#endif /* SWIFT_DIAGNOSTICLIST_H */

include/swift/AST/DiagnosticsClangImporter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
namespace swift {
2424
namespace diag {
2525
// Declare common diagnostics objects with their appropriate types.
26-
#define DIAG(KIND,ID,Options,Text,Signature) \
27-
extern detail::DiagWithArguments<void Signature>::type ID;
26+
#define DIAG(KIND, ID, Group, Options, Text, Signature) \
27+
extern detail::DiagWithArguments<void Signature>::type ID;
2828
#include "DiagnosticsClangImporter.def"
2929
}
3030
}

include/swift/AST/DiagnosticsCommon.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ ERROR(error_no_group_info,none,
4747
NOTE(brace_stmt_suggest_do,none,
4848
"did you mean to use a 'do' statement?", ())
4949

50-
WARNING(error_in_future_swift_version,none,
50+
GROUPED_WARNING(error_in_future_swift_version,error_in_future_swift_version,none,
5151
"%0; this is an error in the Swift %1 language mode",
5252
(DiagnosticInfo *, unsigned))
5353

include/swift/AST/DiagnosticsCommon.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ namespace swift {
5656
using DeclAttribute = const DeclAttribute *;
5757

5858
// Declare common diagnostics objects with their appropriate types.
59-
#define DIAG(KIND,ID,Options,Text,Signature) \
60-
extern detail::DiagWithArguments<void Signature>::type ID;
61-
#define FIXIT(ID, Text, Signature) \
62-
extern detail::StructuredFixItWithArguments<void Signature>::type ID;
59+
#define DIAG(KIND, ID, Group, Options, Text, Signature) \
60+
extern detail::DiagWithArguments<void Signature>::type ID;
61+
#define FIXIT(ID, Text, Signature) \
62+
extern detail::StructuredFixItWithArguments<void Signature>::type ID;
6363
#include "DiagnosticsCommon.def"
6464
} // end namespace diag
6565
} // end namespace swift

include/swift/AST/DiagnosticsDriver.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
namespace swift {
2626
namespace diag {
2727
// Declare common diagnostics objects with their appropriate types.
28-
#define DIAG(KIND,ID,Options,Text,Signature) \
29-
extern detail::DiagWithArguments<void Signature>::type ID;
28+
#define DIAG(KIND, ID, Group, Options, Text, Signature) \
29+
extern detail::DiagWithArguments<void Signature>::type ID;
3030
#include "DiagnosticsDriver.def"
3131
}
3232
}

0 commit comments

Comments
 (0)