7
7
// ===----------------------------------------------------------------------===//
8
8
#include " clang/Driver/BoundsSafetyArgs.h"
9
9
#include " clang/Basic/DiagnosticDriver.h"
10
- #include " clang/Basic/DiagnosticFrontend.h"
11
10
#include " clang/Driver/Options.h"
12
- #include " llvm/ADT/StringSet.h"
13
- #include " llvm/ADT/bit.h"
14
- #include < array>
15
11
16
12
using namespace llvm ::opt;
17
13
using namespace clang ::driver::options;
@@ -20,103 +16,15 @@ namespace clang {
20
16
21
17
namespace driver {
22
18
23
- static void DiagnoseDisabledBoundsSafetyChecks (
24
- LangOptions::BoundsSafetyNewChecksMaskIntTy EnabledChecks,
25
- DiagnosticsEngine *Diags,
26
- LangOptions::BoundsSafetyNewChecksMaskIntTy
27
- IndividualChecksExplicitlyDisabled) {
28
- struct BoundsCheckBatch {
29
- const char *Name;
30
- LangOptionsBase::BoundsSafetyNewChecksMaskIntTy Checks;
31
- };
32
-
33
- // Batches of checks should be ordered with newest first
34
- std::array<BoundsCheckBatch, 2 > Batches = {
35
- {// We deliberately don't include `all` here because that batch
36
- // isn't stable over time (unlike batches like `batch_0`) so we
37
- // don't want to suggest users start using it.
38
- {" batch_0" ,
39
- LangOptions::getBoundsSafetyNewChecksMaskForGroup (" batch_0" )},
40
- {" none" , LangOptions::BS_CHK_None}}};
41
-
42
- LangOptionsBase::BoundsSafetyNewChecksMaskIntTy DiagnosedDisabledChecks =
43
- LangOptions::BS_CHK_None;
44
-
45
- // Loop over all batches except "none"
46
- for (size_t BatchIdx = 0 ; BatchIdx < Batches.size () - 1 ; ++BatchIdx) {
47
- auto ChecksInCurrentBatch = Batches[BatchIdx].Checks ;
48
- auto ChecksInOlderBatch = Batches[BatchIdx + 1 ].Checks ;
49
- auto ChecksInCurrentBatchOnly = ChecksInCurrentBatch & ~ChecksInOlderBatch;
50
- const auto *CurrentBatchName = Batches[BatchIdx].Name ;
51
-
52
- if ((EnabledChecks & ChecksInCurrentBatchOnly) == ChecksInCurrentBatchOnly)
53
- continue ; // All checks in batch are enabled. Nothing to diagnose.
54
-
55
- // Diagnose disabled bounds checks
56
-
57
- if ((EnabledChecks & ChecksInCurrentBatchOnly) == 0 ) {
58
- // None of the checks in the current batch are enabled. Diagnose this
59
- // once for all the checks in the batch.
60
- if ((DiagnosedDisabledChecks & ChecksInCurrentBatchOnly) !=
61
- ChecksInCurrentBatchOnly) {
62
- Diags->Report (diag::warn_bounds_safety_new_checks_none)
63
- << CurrentBatchName;
64
- DiagnosedDisabledChecks |= ChecksInCurrentBatchOnly;
65
- }
66
- continue ;
67
- }
68
-
69
- // Some (but not all) checks are disabled in the current batch. Iterate over
70
- // each check in the batch and emit a diagnostic for each disabled check
71
- // in the batch.
72
- assert (ChecksInCurrentBatch > 0 );
73
- auto FirstCheckInBatch = 1 << llvm::countr_zero (ChecksInCurrentBatch);
74
- for (size_t CheckBit = FirstCheckInBatch;
75
- CheckBit <= LangOptions::BS_CHK_MaxMask; CheckBit <<= 1 ) {
76
- assert (CheckBit != 0 );
77
- if ((CheckBit & ChecksInCurrentBatch) == 0 )
78
- continue ; // Check not in batch
79
-
80
- if (EnabledChecks & CheckBit)
81
- continue ; // Check is active
82
-
83
- // Diagnose disabled check
84
- if (!(DiagnosedDisabledChecks & CheckBit)) {
85
- size_t CheckNumber = llvm::countr_zero (CheckBit);
86
- // If we always suggested enabling the current batch that
87
- // could be confusing if the user passed something like
88
- // `-fbounds-safety-bringup-missing-checks=batch_0
89
- // -fno-bounds-safety-bringup-missing-checks=access_size`. To avoid
90
- // this we detect when the check corresponding to `CheckBit` has been
91
- // explicitly disabled on the command line and in that case we suggeset
92
- // removing the flag.
93
- bool SuggestRemovingFlag =
94
- CheckBit & IndividualChecksExplicitlyDisabled;
95
- Diags->Report (diag::warn_bounds_safety_new_checks_mixed)
96
- << CheckNumber << SuggestRemovingFlag << CurrentBatchName;
97
- DiagnosedDisabledChecks |= CheckBit;
98
- }
99
- }
100
- }
101
- }
102
-
103
19
LangOptions::BoundsSafetyNewChecksMaskIntTy
104
20
ParseBoundsSafetyNewChecksMaskFromArgs (const llvm::opt::ArgList &Args,
105
- DiagnosticsEngine *Diags,
106
- bool DiagnoseMissingChecks) {
107
- assert ((!DiagnoseMissingChecks || Diags) &&
108
- " Cannot diagnose missing checks when Diags is a nullptr" );
109
- LangOptions::BoundsSafetyNewChecksMaskIntTy
110
- IndividualChecksExplicitlyDisabled = LangOptions::BS_CHK_None;
21
+ DiagnosticsEngine *Diags) {
111
22
auto FilteredArgs =
112
23
Args.filtered (OPT_fbounds_safety_bringup_missing_checks_EQ,
113
24
OPT_fno_bounds_safety_bringup_missing_checks_EQ);
114
25
if (FilteredArgs.empty ()) {
115
26
// No flags present. Use the default
116
- auto Result = LangOptions::getDefaultBoundsSafetyNewChecksMask ();
117
- DiagnoseDisabledBoundsSafetyChecks (Result, Diags,
118
- IndividualChecksExplicitlyDisabled);
119
- return Result;
27
+ return LangOptions::getDefaultBoundsSafetyNewChecksMask ();
120
28
}
121
29
122
30
// If flags are present then start with BS_CHK_None as the initial mask and
@@ -127,11 +35,6 @@ ParseBoundsSafetyNewChecksMaskFromArgs(const llvm::opt::ArgList &Args,
127
35
// All the options will be applied as masks in the command line order, to make
128
36
// it easier to enable all but certain checks (or disable all but certain
129
37
// checks).
130
- const auto Batch0Checks =
131
- LangOptions::getBoundsSafetyNewChecksMaskForGroup (" batch_0" );
132
- const auto AllChecks =
133
- LangOptions::getBoundsSafetyNewChecksMaskForGroup (" all" );
134
- bool Errors = false ;
135
38
for (const Arg *A : FilteredArgs) {
136
39
for (const char *Value : A->getValues ()) {
137
40
std::optional<LangOptions::BoundsSafetyNewChecksMaskIntTy> Mask =
@@ -148,16 +51,17 @@ ParseBoundsSafetyNewChecksMaskFromArgs(const llvm::opt::ArgList &Args,
148
51
.Case (" libc_attributes" , LangOptions::BS_CHK_LibCAttributes)
149
52
.Case (" array_subscript_agg" ,
150
53
LangOptions::BS_CHK_ArraySubscriptAgg)
151
- .Case (" all" , AllChecks)
152
- .Case (" batch_0" , Batch0Checks)
54
+ .Case (" all" ,
55
+ LangOptions::getBoundsSafetyNewChecksMaskForGroup (" all" ))
56
+ .Case (
57
+ " batch_0" ,
58
+ LangOptions::getBoundsSafetyNewChecksMaskForGroup (" batch_0" ))
153
59
.Case (" none" , LangOptions::BS_CHK_None)
154
60
.Default (std::nullopt);
155
-
156
61
if (!Mask) {
157
62
if (Diags)
158
63
Diags->Report (diag::err_drv_invalid_value)
159
64
<< A->getSpelling () << Value;
160
- Errors = true ;
161
65
break ;
162
66
}
163
67
@@ -177,7 +81,6 @@ ParseBoundsSafetyNewChecksMaskFromArgs(const llvm::opt::ArgList &Args,
177
81
<< A->getSpelling () << Value
178
82
<< (IsPosFlag ? " -fno-bounds-safety-bringup-missing-checks"
179
83
: " -fbounds-safety-bringup-missing-checks" );
180
- Errors = true ;
181
84
break ;
182
85
}
183
86
@@ -188,25 +91,8 @@ ParseBoundsSafetyNewChecksMaskFromArgs(const llvm::opt::ArgList &Args,
188
91
OPT_fno_bounds_safety_bringup_missing_checks_EQ));
189
92
Result &= ~(*Mask);
190
93
}
191
-
192
- // Update which checks have been explicitly disabled. E.g.
193
- // `-fno-bounds-safety-bringup-missing-checks=access_size`.
194
- if (llvm::has_single_bit (*Mask)) {
195
- // A single check was enabled/disabled
196
- if (IsPosFlag)
197
- IndividualChecksExplicitlyDisabled &= ~(*Mask);
198
- else
199
- IndividualChecksExplicitlyDisabled |= *Mask;
200
- } else {
201
- // A batch of checks were enabled/disabled. Any checks in that batch
202
- // are no longer explicitly set.
203
- IndividualChecksExplicitlyDisabled &= ~(*Mask);
204
- }
205
94
}
206
95
}
207
- if (DiagnoseMissingChecks && Diags && !Errors)
208
- DiagnoseDisabledBoundsSafetyChecks (Result, Diags,
209
- IndividualChecksExplicitlyDisabled);
210
96
return Result;
211
97
}
212
98
0 commit comments