diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 8d4aa2868f40..ad673f8198ea 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -62,6 +62,8 @@ def ext_gnu_indirect_goto : Extension< "use of GNU indirect-goto extension">, InGroup; def ext_gnu_address_of_label : Extension< "use of GNU address-of-label extension">, InGroup; +def ext_gnu_local_label : Extension< + "use of GNU locally declared label extension">, InGroup; def ext_gnu_statement_expr : Extension< "use of GNU statement expression extension">, InGroup; def ext_gnu_conditional_expr : Extension< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 48f3e90ee1e0..8d8cf0991295 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1414,7 +1414,8 @@ public: QualType T1, QualType T2, UnresolvedSetImpl &Functions); - LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc); + LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, + bool isLocalLabel = false); DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class); CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); diff --git a/clang/lib/AST/StmtDumper.cpp b/clang/lib/AST/StmtDumper.cpp index 490e2eea6e30..846bd4ce1441 100644 --- a/clang/lib/AST/StmtDumper.cpp +++ b/clang/lib/AST/StmtDumper.cpp @@ -282,6 +282,8 @@ void StmtDumper::DumpDeclarator(Decl *D) { UD->getTargetNestedNameDecl()->print(OS, PrintingPolicy(UD->getASTContext().getLangOptions())); OS << ";\""; + } else if (LabelDecl *LD = dyn_cast(D)) { + OS << "label " << LD->getNameAsString(); } else { assert(0 && "Unexpected decl"); } diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 97dbf0ba3161..22f28197c60c 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -70,7 +70,6 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Friend: case Decl::FriendTemplate: case Decl::Block: - case Decl::Label: assert(0 && "Declaration not should not be in declstmts!"); case Decl::Function: // void X(); case Decl::Record: // struct/union/class X; @@ -82,6 +81,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::UsingDirective: // using namespace X; [C++] case Decl::NamespaceAlias: case Decl::StaticAssert: // static_assert(X, ""); [C++0x] + case Decl::Label: // __label__ x; // None of these decls require codegen support. return; diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 2c4ab655aec2..2d9758333f0c 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -476,12 +476,41 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'. - // TODO: "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are - // only allowed at the start of a compound stmt regardless of the language. - StmtVector Stmts(Actions); - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + // "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are + // only allowed at the start of a compound stmt regardless of the language. + while (Tok.is(tok::kw___label__)) { + SourceLocation LabelLoc = ConsumeToken(); + Diag(LabelLoc, diag::ext_gnu_local_label); + + llvm::SmallVector DeclsInGroup; + while (1) { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + break; + } + + IdentifierInfo *II = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, true)); + + if (!Tok.is(tok::comma)) + break; + ConsumeToken(); + } + + DeclSpec DS; + DeclGroupPtrTy Res = Actions.FinalizeDeclaratorGroup(getCurScope(), DS, + DeclsInGroup.data(), DeclsInGroup.size()); + StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation()); + + ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); + if (R.isUsable()) + Stmts.push_back(R.release()); + } + + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { if (Tok.is(tok::annot_pragma_unused)) { HandlePragmaUnused(); continue; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index b7740bf5c082..789f9c9f4ff3 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2760,10 +2760,18 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, /*InBaseClass=*/false, Consumer, Visited); } -LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc) { +/// LookupOrCreateLabel - Do a name lookup of a label with the specified name. +/// If isLocalLabel is true, then this is a definition of an __label__ label +/// name, otherwise it is a normal label definition or use. +LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, + bool isLocalLabel) { // Do a lookup to see if we have a label with this name already. - NamedDecl *Res = LookupSingleName(CurScope, II, Loc, LookupLabel, - NotForRedeclaration); + NamedDecl *Res = 0; + + // Local label definitions always shadow existing labels. + if (!isLocalLabel) + Res = LookupSingleName(CurScope, II, Loc, LookupLabel, NotForRedeclaration); + // If we found a label, check to see if it is in the same context as us. When // in a Block, we don't want to reuse a label in an enclosing function. if (Res && Res->getDeclContext() != CurContext) @@ -2772,7 +2780,8 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc) { if (Res == 0) { // If not forward referenced or defined already, create the backing decl. Res = LabelDecl::Create(Context, CurContext, Loc, II); - PushOnScopeChains(Res, CurScope->getFnParent(), true); + PushOnScopeChains(Res, isLocalLabel ? CurScope : CurScope->getFnParent(), + true); } return cast(Res); diff --git a/clang/test/Parser/goto.c b/clang/test/Parser/goto.c index 32051dc677ec..a3e01174eb94 100644 --- a/clang/test/Parser/goto.c +++ b/clang/test/Parser/goto.c @@ -1,6 +1,30 @@ /* RUN: %clang_cc1 -fsyntax-only -verify %s */ -void foo() { +void test1() { goto ; /* expected-error {{expected identifier}} */ } + + +void test2() { + l: /* expected-note {{previous definition is here}} */ + + { + __label__ l; + l: goto l; + } + + { + __label__ l; + __label__ h; /* expected-error {{use of undeclared label 'h'}} */ + l: goto l; + } + + /* PR3429 & rdar://8287027 + */ + { + l: /* expected-error {{redefinition of label 'l'}} */ + ; + } + +}