mirror of https://github.com/microsoft/clang.git
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! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194869 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
0a5a7c129f
commit
93982a7557
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -9,3 +9,7 @@ void f() {
|
|||
goto d;
|
||||
return;
|
||||
}
|
||||
|
||||
void PR8455() {
|
||||
L: __attribute__((unused)) return; // ok, no semicolon required
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue