[cfe-commits] Patch - Add fix-it hint for missing case keyword within a switch scope
Douglas Gregor
dgregor at apple.com
Wed Apr 20 07:35:04 PDT 2011
On Apr 19, 2011, at 5:19 PM, Richard Trieu wrote:
> I have reworked the program flow. Instead of tentative parsing, the already parsed expression is reused within the case statement parsing following colon detection.
I like this much better! A few more comments:
Index: include/clang/Sema/Scope.h
===================================================================
--- include/clang/Sema/Scope.h (revision 129825)
+++ include/clang/Sema/Scope.h (working copy)
@@ -75,7 +75,10 @@
/// ObjCMethodScope - This scope corresponds to an Objective-C method body.
/// It always has FnScope and DeclScope set as well.
- ObjCMethodScope = 0x400
+ ObjCMethodScope = 0x400,
+
+ /// SwitchScope - This is a scope that corresponds to a switch statement.
+ SwitchScope = 0x800
};
private:
/// The parent scope for this scope. This is null for the translation-unit
@@ -260,6 +263,14 @@
return getFlags() & Scope::AtCatchScope;
}
+ /// isSwitchScope - Return true if this scope is a switch scope.
+ bool isSwitchScope() const {
+ for (const Scope *S = this; S; S = S->getParent()) {
+ if (S->getFlags() & Scope::SwitchScope)
+ return true;
+ }
+ }
+
This is going to search all the way up the scope stack for a switch anywhere, which isn't necessarily the same thing as being in a switch statement because there could be inner classes/blocks/etc. For example, we'll incorrectly suggest the 'case' keyword for this example:
void f(int x) {
switch (x) {
case 1: {
struct Inner {
void g() {
1: x = 17;
}
};
break;
}
}
}
I see two solutions:
1) Prevent isSwitchScope() from walking through function declarations/blocks/etc. Or, only jump up one scope level (e.g., from the compound statement out to the switch) when checking for a switch scope, since case statements rarely show up anywhere else.
2) Add a Sema function isInSwitchStatement() and use that in the parser.
@@ -251,8 +266,11 @@
/// 'case' constant-expression ':' statement
/// [GNU] 'case' constant-expression '...' constant-expression ':' statement
///
-StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) {
- assert(Tok.is(tok::kw_case) && "Not a case stmt!");
+StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase,
+ ExprResult Expr) {
+ if (!MissingCase) {
+ assert(Tok.is(tok::kw_case) && "Not a case stmt!");
+ }
How about:
assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!");
@@ -133,6 +136,18 @@
ConsumeToken();
return StmtError();
}
+
+ if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() &&
+ Expr.get()->isIntegerConstantExpr(Actions.Context)) {
There are two issues here. The first is that Expr::isIntegerConstantExpr() isn't safe for type- or value-dependent expressions, so we now crash on this ill-formed code:
template<typename T>
struct X {
enum { E };
void f(int x) {
switch (x) {
E: break;
E+1: break;
}
}
};
The second issue is that the parser shouldn't probe the AST directly. Instead, please add a function into Sema that performs the semantic analysis and decides whether this expression was meant to be part of a case statement. That function should allow the correction for type-dependent expressions, value-dependent expressions with integral or enumeration type, and non-dependent, integral constant expressions.
Finally, I had two thoughts for follow-on patches:
1) Given code like this:
enum E { A };
void f(int e) {
switch (e) {
A: break;
}
}
Under -Wunused-label, we warn about 'A'. However, it would be very cool to give a warning like:
warning: unused label 'A' also refers to an %select{integeral|enumeration}0 value within a switch statement
note: did you mean to make this a case statement?
(with a "case " Fix-It on the note).
2) It occurs to me that, if we're in a non-switch statement context and we we see a ':' after an expression, the ':' is probably a typo for ';'. It may be worth adding that recovery + Fix-It as well.
Thanks for working on this!
- Doug
- Doug
> On Fri, Apr 15, 2011 at 2:03 PM, Douglas Gregor <dgregor at apple.com> wrote:
>
> On Apr 15, 2011, at 11:58 AM, Richard Trieu wrote:
>
> > When a valid expression is followed by a colon inside a switch scope, suggest a fix-it hint to insert a case before the expression.
> >
> > int f1(int i) {
> > switch (i) {
> > 0: return 1;
> > default: return 0;
> > }
> > }
> >
> > case.cc:3:4: error: expected 'case' keyword before expression
> > 0: return 1;
> > ^
> > case
>
> Cool idea, but this...
>
> + // If a case statement is missing, then back-track to this point and
> + // insert case keyword.
> + Token OldToken = Tok;
> + TentativeParsingAction TPA(*this);
>
> is a huge performance problem, since tentative parsing is expensive and should be avoided except after an error occurs or when required by the language.
>
> Is there a way to make this diagnostic kick in only when an error is imminent, e.g., because we've seen <expression> ':' somewhere within a switch statement?
>
> - Doug
>
> <missing-case-keyword2.patch>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20110420/b5d5a68f/attachment.html>
More information about the cfe-commits
mailing list