-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Control analysis-based diagnostics with #pragma #136323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 6 commits
3beecb2
e9f2cd4
17fcd1f
7e116dc
1644401
cf27e93
f561ae3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -202,6 +202,43 @@ class SemaPPCallbacks : public PPCallbacks { | |
break; | ||
} | ||
} | ||
void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, | ||
diag::Severity Mapping, StringRef Str) override { | ||
// If one of the analysis-based diagnostics was enabled while processing | ||
// a function, we want to note it in the analysis-based warnings so they | ||
// can be run at the end of the function body even if the analysis warnings | ||
// are disabled at that point. | ||
SmallVector<diag::kind, 256> GroupDiags; | ||
diag::Flavor Flavor = | ||
Str[1] == 'W' ? diag::Flavor::WarningOrError : diag::Flavor::Remark; | ||
StringRef Group = Str.substr(2); | ||
|
||
if (S->PP.getDiagnostics().getDiagnosticIDs()->getDiagnosticsInGroup( | ||
Flavor, Group, GroupDiags)) | ||
return; | ||
|
||
for (diag::kind K : GroupDiags) { | ||
// Note: the cases in this switch should be kept in sync with the | ||
// diagnostics in AnalysisBasedWarnings::getPolicyInEffectAt(). | ||
AnalysisBasedWarnings::Policy &Override = | ||
S->AnalysisWarnings.getPolicyOverrides(); | ||
switch (K) { | ||
default: break; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So every new analysis-based warning needs to be added to this list right? How weird are the consequences of forgetting it? It might be a good idea to make a unified list of analysis-based warnings. (Or like, make it a flag in (Probably out of scope for this patch. Sounds like a lot of work. There could be easier ways to check this. Could also be too restrictive in practice.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At the moment, yes. As a follow-up, I would wonder if we could auto-generate this from tablegen. Though, in this patch, we could perhaps instead of doing this override, have the policy store a LIST of override diagnostics, that we then check are in the list. So this would instead of this whole switch do:
That would work for ALL diagnostics, at the expense of a somewhat significant size increase. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Correct, but thankfully we don't add those very often.
If you add it to AnalysisBasedDiagnostics.cpp and not to Sema.cpp, the analysis will work everywhere except for pragma regions like this. If you add it to Sema.cpp but not AnalysisBasicDiagnostics.cpp, the only time the analysis will work will be within pragma regions. So either is weird, but one seems more likely to slip through the cracks than the other.
Yeah, it would be nice if this could be tablegenned. But there are so few analysis-based warnings and there's no good mechanism to know when you forget to add the correct marking to the .td file that I can think of so far.
Yeah, I'd prefer to punt on that. :-) |
||
case diag::warn_unreachable: | ||
case diag::warn_unreachable_break: | ||
case diag::warn_unreachable_return: | ||
case diag::warn_unreachable_loop_increment: | ||
Override.enableCheckUnreachable = true; | ||
break; | ||
case diag::warn_double_lock: | ||
Override.enableThreadSafetyAnalysis = true; | ||
break; | ||
case diag::warn_use_in_invalid_state: | ||
Override.enableConsumedAnalysis = true; | ||
break; | ||
} | ||
} | ||
} | ||
}; | ||
|
||
} // end namespace sema | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// RUN: %clang_cc1 -fsyntax-only -verify -Werror=unreachable-code-aggressive %s | ||
|
||
// Test that analysis-based warnings honor #pragma diagnostic controls. | ||
|
||
struct [[clang::consumable(unconsumed)]] Linear { | ||
[[clang::return_typestate(unconsumed)]] | ||
Linear() {} | ||
[[clang::callable_when(consumed)]] | ||
~Linear() {} | ||
}; | ||
|
||
int a() { | ||
Linear l; | ||
return 0; // No -Wconsumed diagnostic, analysis is not enabled. | ||
return 1; // expected-error {{'return' will never be executed}} | ||
} | ||
|
||
#pragma clang diagnostic push | ||
#pragma clang diagnostic error "-Wconsumed" | ||
int b() { | ||
Linear l; | ||
return 0; // expected-error {{invalid invocation of method '~Linear' on object 'l' while it is in the 'unconsumed' state}} | ||
return 1; // expected-error {{'return' will never be executed}} | ||
} | ||
#pragma clang diagnostic pop | ||
|
||
int c() { | ||
#pragma clang diagnostic push | ||
#pragma clang diagnostic error "-Wconsumed" | ||
Linear l; | ||
return 0; // expected-error {{invalid invocation of method '~Linear' on object 'l' while it is in the 'unconsumed' state}} | ||
return 1; // expected-error {{'return' will never be executed}} | ||
#pragma clang diagnostic pop | ||
} | ||
|
||
int d() { | ||
#pragma clang diagnostic push | ||
#pragma clang diagnostic error "-Wconsumed" | ||
#pragma clang diagnostic ignored "-Wunreachable-code-aggressive" | ||
Linear l; | ||
return 0; // expected-error {{invalid invocation of method '~Linear' on object 'l' while it is in the 'unconsumed' state}} | ||
return 1; // Diagnostic is ignored | ||
} | ||
#pragma clang diagnostic pop | ||
|
||
int e() { | ||
#pragma clang diagnostic push | ||
#pragma clang diagnostic error "-Wconsumed" | ||
#pragma clang diagnostic ignored "-Wunreachable-code-aggressive" | ||
Linear l; | ||
return 0; // expected-error {{invalid invocation of method '~Linear' on object 'l' while it is in the 'unconsumed' state}} | ||
return 1; // Diagnostic is ignored | ||
#pragma clang diagnostic pop | ||
} | ||
|
||
int f() { | ||
Linear l; | ||
return 0; // No -Wconsumed diagnostic, analysis is not enabled | ||
return 1; // expected-error {{'return' will never be executed}} | ||
#pragma clang diagnostic push | ||
#pragma clang diagnostic ignored "-Wunreachable-code-aggressive" | ||
} | ||
#pragma clang diagnostic pop | ||
|
||
int g() { | ||
Linear l; | ||
return 0; // No -Wconsumed diagnostic, the diagnostic generated at } is not enabled on this line. | ||
Sirraide marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return 1; // expected-error {{'return' will never be executed}} | ||
#pragma clang diagnostic push | ||
#pragma clang diagnostic warning "-Wconsumed" | ||
} | ||
#pragma clang diagnostic pop | ||
|
||
int h() { | ||
#pragma clang diagnostic push | ||
#pragma clang diagnostic error "-Wconsumed" | ||
#pragma clang diagnostic ignored "-Wunreachable-code-aggressive" | ||
#pragma clang diagnostic pop | ||
|
||
Linear l; | ||
return 0; // No -Wconsumed diagnostic, the diagnostic generated at } is not enabled on this line. | ||
return 1; // expected-error {{'return' will never be executed}} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests show this working but.... where on earth are these set?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overrides are set in
SemaPPCallback::PragmaDiagnostic()
, the others come fromAnalysisBasedWarnings::getPolicyInEffectAt()