PR8455: Handle an attribute between a goto label and a variable declaration per

the GNU documentation: the attribute only appertains to the label if it is
followed by a semicolon. Based on a patch by Aaron Ballman!

llvm-svn: 194869
This commit is contained in:
Richard Smith 2013-11-15 22:45:29 +00:00
parent 9c13dd027b
commit a3e01cf822
4 changed files with 78 additions and 6 deletions

View File

@ -516,11 +516,40 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) {
// identifier ':' statement
SourceLocation ColonLoc = ConsumeToken();
// Read label attributes, if present. attrs will contain both C++11 and GNU
// attributes (if present) after this point.
MaybeParseGNUAttributes(attrs);
// Read label attributes, if present.
StmtResult SubStmt;
if (Tok.is(tok::kw___attribute)) {
ParsedAttributesWithRange TempAttrs(AttrFactory);
ParseGNUAttributes(TempAttrs);
StmtResult SubStmt(ParseStatement());
// In C++, GNU attributes only apply to the label if they are followed by a
// semicolon, to disambiguate label attributes from attributes on a labeled
// declaration.
//
// This doesn't quite match what GCC does; if the attribute list is empty
// and followed by a semicolon, GCC will reject (it appears to parse the
// attributes as part of a statement in that case). That looks like a bug.
if (!getLangOpts().CPlusPlus || Tok.is(tok::semi))
attrs.takeAllFrom(TempAttrs);
else if (isDeclarationStatement()) {
StmtVector Stmts;
// FIXME: We should do this whether or not we have a declaration
// statement, but that doesn't work correctly (because ProhibitAttributes
// can't handle GNU attributes), so only call it in the one case where
// GNU attributes are allowed.
SubStmt = ParseStatementOrDeclarationAfterAttributes(
Stmts, /*OnlyStmts*/ true, 0, TempAttrs);
if (!TempAttrs.empty() && !SubStmt.isInvalid())
SubStmt = Actions.ProcessStmtAttributes(
SubStmt.get(), TempAttrs.getList(), TempAttrs.Range);
} else {
Diag(Tok, diag::err_expected_semi_after) << "__attribute__";
}
}
// If we've not parsed a statement yet, parse one now.
if (!SubStmt.isInvalid() && !SubStmt.isUsable())
SubStmt = ParseStatement();
// Broken substmt shouldn't prevent the label from being added to the AST.
if (SubStmt.isInvalid())
@ -557,7 +586,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
// out of stack space in our recursive descent parser. As a special case,
// flatten this recursion into an iterative loop. This is complex and gross,
// but all the grossness is constrained to ParseCaseStatement (and some
// wierdness in the actions), so this is just local grossness :).
// weirdness in the actions), so this is just local grossness :).
// TopLevelCase - This is the highest level we have parsed. 'case 1' in the
// example above.

View File

@ -95,3 +95,19 @@ void *TestVariadicUnsigned1(int) __attribute__((alloc_size(1)));
void *TestVariadicUnsigned2(int, int) __attribute__((alloc_size(1,2)));
// CHECK: FunctionDecl{{.*}}TestVariadicUnsigned2
// CHECK: AllocSizeAttr{{.*}} 0 1
void TestLabel() {
L: __attribute__((unused)) int i;
// CHECK: LabelStmt{{.*}}'L'
// CHECK: VarDecl{{.*}}i 'int'
// CHECK-NEXT: UnusedAttr{{.*}}
M: __attribute(()) int j;
// CHECK: LabelStmt {{.*}} 'M'
// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl {{.*}} j 'int'
N: __attribute(()) ;
// CHECK: LabelStmt {{.*}} 'N'
// CHECK-NEXT: NullStmt
}

View File

@ -9,3 +9,7 @@ void f() {
goto d;
return;
}
void PR8455() {
L: __attribute__((unused)) return; // ok, no semicolon required
}

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -verify %s
// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -Wunused-label -verify %s
template<typename T> void f() {
T t;
t = 17;
@ -128,3 +128,26 @@ namespace ctor_with_cleanups {
}
#include "Inputs/warn-unused-variables.h"
namespace PR8455 {
void f() {
A: // expected-warning {{unused label 'A'}}
__attribute__((unused)) int i; // attribute applies to variable
B: // attribute applies to label
__attribute__((unused)); int j; // expected-warning {{unused variable 'j'}}
}
void g() {
C: // unused label 'C' will not appear here because an error occurs
__attribute__((unused))
#pragma weak unused_local_static // expected-error {{expected ';' after __attribute__}}
;
}
void h() {
D: // expected-warning {{unused label 'D'}}
#pragma weak unused_local_static
__attribute__((unused)) // expected-warning {{declaration does not declare anything}}
;
}
}