-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[Sema] Warn about omitting deprecated enumerator in switch #138562
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
Conversation
This undoes part of 3e4e3b1 which added the "Omitting a deprecated constant is ok; it should never materialize." logic. That seems wrong: deprecated means the enumerator is likely to be removed in future versions, not that it canot materialize.
@llvm/pr-subscribers-clang Author: Hans Wennborg (zmodem) ChangesThis undoes part of 3e4e3b1 which added the "Omitting a deprecated constant is ok; it should never materialize." logic. That seems wrong: deprecated means the enumerator is likely to be removed in future versions, not that it cannot materialize. Full diff: https://github.com/llvm/llvm-project/pull/138562.diff 2 Files Affected:
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index e8c1f8490342a..990d2fadaf5aa 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -1667,8 +1667,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// Don't warn about omitted unavailable EnumConstantDecls.
switch (EI->second->getAvailability()) {
case AR_Deprecated:
- // Omitting a deprecated constant is ok; it should never materialize.
+ // Deprecated enumerators still need to be handled: they may be
+ // deprecated, but can still occur.
+ break;
+
case AR_Unavailable:
+ // Omitting an unavailable enumerator is ok; it should never occur.
continue;
case AR_NotYetIntroduced:
diff --git a/clang/test/Sema/switch-availability.c b/clang/test/Sema/switch-availability.c
index 888edddac463d..b4f8726addc0b 100644
--- a/clang/test/Sema/switch-availability.c
+++ b/clang/test/Sema/switch-availability.c
@@ -15,7 +15,7 @@ enum SwitchTwo {
};
void testSwitchTwo(enum SwitchTwo st) {
- switch (st) {} // expected-warning{{enumeration values 'Vim' and 'Emacs' not handled in switch}}
+ switch (st) {} // expected-warning{{enumeration values 'Ed', 'Vim' and 'Emacs' not handled in switch}}
}
enum SwitchThree {
|
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.
Thanks! I think this is sufficiently niche that we don't need a flag flip to manage the diagnostic change fallout.
Fly-by comment: I drafted the following alternative comment in another thread. Please feel free to disregard as I don't know the tone and style of comments in these files. (But I appreciate your consideration for the contents in the message I'd like to see!)
|
My patch changes the behavior so that deprecated constants are not ignored by the switch coverage warning. |
I wonder if we should also do something special about the If the user fixes the -Wswitch / -Wreturn-type warnings from
They will get Maybe we should suppress that warning for switch cases? Or suggest adding a |
I think silencing the warning is better than suggesting a default case, which may not be considered good practice. |
I've added suppression of deprecated values in case expressions. Please take another look! |
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.
I'm OK with this, but I feel like this is creating scope creep. Now we have a special Wdeprecated-declarations carveouts for switches, but if you unpack the switch into if / else chain comparisons, you get deprecation warnings. Should we disable deprecation warnings that directly compare enumerators? I wouldn't want to expand scope that much.
It is possible to write code that avoids mentioning the deprecated enum (add a default, and/or fallthrough code) and silences -Wreturn-type, so I have a soft preference for going back to the old version.
clang/include/clang/Sema/Sema.h
Outdated
@@ -6767,6 +6767,9 @@ class Sema final : public SemaBase { | ||
}; | ||
std::optional<InitializationContext> DelayedDefaultInitializationContext; | ||
|
||
/// Whether evaluating an expression for a switch case label. |
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.
supernit: pack it with the contextual bools above, for both layout reasons and because it shows there's prior art
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.
Done.
Agreed, that it is a bit inconsistent. There is prior art though: ba87c62 makes exactly the same carve-out for -Wunguarded-availability (though the mechanism is different). |
I don't think we should suppress the warning; the enumerator is deprecated and the user should be told that when they enable deprecation warnings. Isn't the better solution in this case for the user to use |
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.
I think I expected a deprecated warning but I agree with the rest of the change. I would be ok w/ @cor3ntin suggestion.
But the user also needs to handle it in the switch: deprecated doesn't mean the enumerator can't occur (a recent experience of this motivated the patch ;)
I'm not sure I'm following. I think this is exactly ba87c62 but for deprecated constants, and that we should handle it the same.
I'd be okay with this too. We'd turn it off though, and would it actually catch real issues? |
Sure! But both sides of that are "the problem"; once you mark the enumerator as deprecated, you'll get diagnostics when you assign that value or when you test against that value.
Oh good point, that case still needs to exist to handle the enumerator. I was thinking about it handling the
I can see the rationale for handling both the same way. But the flip side is, then you get false negatives which can also come up legitimately. Consider:
That code will continue to work great right up until the enumerator is removed. |
I'm not sure, I think our perspectives as compiler people might be a bit off base. We're always forming closed algebraic sum types, like variants, AST nodes, that kind of thing. I think normal programs dealing with untrusted input coming from a file or over the wire typically need to be more conservative, and pushing users towards adding a
To Aaron's point about deprecation being a tool for removal, if the goal of deprecation is to remove the enumerator, then we do want folks to use |
Thanks Aaron, that's a good example. This is a pickle; it doesn't seem like there's an obviously Right Solution(tm) here. I think we're agreeing on the first part, that unhandled deprecated enums should trigger the "not covered" warning. Some users will prefer to handle that with a Corentin's flag suggestion seems like the best way to satisfy both camps. I've updated the PR. |
@@ -6009,6 +6009,8 @@ def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to th | ||
def err_undeclared_use : Error<"use of undeclared %0">; | ||
def warn_deprecated : Warning<"%0 is deprecated">, | ||
InGroup<DeprecatedDeclarations>; | ||
def warn_deprecated_switch_case : Warning<"%0 is deprecated">, |
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.
You can reuse diagnostic text with warn_deprecated.Summary
. See other examples like:
def ext_vla_cxx_in_gnu_mode : Extension<ext_vla_cxx.Summary>,
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.
Thanks! Done.
That's the same conclusion I'm coming to. These situations are kind of mutually exclusive.
Yup!
I agree, thank you for heading that direction (and good suggestion @cor3ntin)! |
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.
Please add a release note to clang/docs/ReleaseNotes.rst
so users know about the new functionality and flag.
Otherwise, LGTM!
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.
Thanks!
…switch-case To make it more clear that it's a subset of -Wdeprecated-declarations. Follow-up to llvm#138562
…switch-case (llvm#141779) To make it more clear that it's a subset of -Wdeprecated-declarations. Follow-up to llvm#138562
This undoes part of 3e4e3b1 which added the "Omitting a deprecated constant is ok; it should never materialize." logic. That seems wrong: deprecated means the enumerator is likely to be removed in future versions, not that it cannot materialize. Also move warnings about the use of deprecated enumerators in switch cases behind a separate flag, -Wdeprecated-switch-case, for users who wish to handle such enums explicitly and suppress the warning.
…switch-case (llvm#141779) To make it more clear that it's a subset of -Wdeprecated-declarations. Follow-up to llvm#138562
This undoes part of 3e4e3b1 which added the "Omitting a deprecated constant is ok; it should never materialize." logic.
That seems wrong: deprecated means the enumerator is likely to be removed in future versions, not that it cannot materialize.