]> granicus.if.org Git - clang/commitdiff
implement basic support for __label__. I wouldn't be shocked if there are
authorChris Lattner <sabre@nondot.org>
Fri, 18 Feb 2011 02:08:43 +0000 (02:08 +0000)
committerChris Lattner <sabre@nondot.org>
Fri, 18 Feb 2011 02:08:43 +0000 (02:08 +0000)
bugs from other clients that don't expect to see a LabelDecl in a DeclStmt,
but if so they should be easy to fix.

This implements most of PR3429 and rdar://8287027

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125817 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticParseKinds.td
include/clang/Sema/Sema.h
lib/AST/StmtDumper.cpp
lib/CodeGen/CGDecl.cpp
lib/Parse/ParseStmt.cpp
lib/Sema/SemaLookup.cpp
test/Parser/goto.c

index 8d4aa2868f40bc669ade79365f6fe8f868f65871..ad673f8198eaffdc1cd05e65157565d4c8da17f9 100644 (file)
@@ -62,6 +62,8 @@ def ext_gnu_indirect_goto : Extension<
   "use of GNU indirect-goto extension">, InGroup<GNU>;
 def ext_gnu_address_of_label : Extension<
   "use of GNU address-of-label extension">, InGroup<GNU>;
+def ext_gnu_local_label : Extension<
+  "use of GNU locally declared label extension">, InGroup<GNU>;
 def ext_gnu_statement_expr : Extension<
   "use of GNU statement expression extension">, InGroup<GNU>;
 def ext_gnu_conditional_expr : Extension<
index 48f3e90ee1e051f9e2679d67c8d4f9d2b1afbb5d..8d8cf0991295421775734f5ce4fa73b2efbce046 100644 (file)
@@ -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);
index 490e2eea6e3018adce6d87d252c8193f488f038f..846bd4ce14417b2c804a68d97df60a15e18b307a 100644 (file)
@@ -282,6 +282,8 @@ void StmtDumper::DumpDeclarator(Decl *D) {
     UD->getTargetNestedNameDecl()->print(OS,
         PrintingPolicy(UD->getASTContext().getLangOptions()));
     OS << ";\"";
+  } else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
+    OS << "label " << LD->getNameAsString();
   } else {
     assert(0 && "Unexpected decl");
   }
index 97dbf0ba3161ca468b65efa8ac20ae01a3a29ddb..22f28197c60ccf000ff507132e4cc4eccb80adaa 100644 (file)
@@ -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;
 
index 2c4ab655aec22af931c78dff40b3fcd59813a842..2d9758333f0c865047b764842fa5a00d4c4121e2 100644 (file)
@@ -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<Decl *, 8> 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;
index b7740bf5c0828f97404509d27ef863adf09a8bb1..789f9c9f4ff389ac909f144da6f96cac2d4d2261 100644 (file)
@@ -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<LabelDecl>(Res);
index 32051dc677eca7ef85bbe12e1ee4b57894f04f8a..a3e01174eb94f5a18aa7d6af5ed09934aecc6e82 100644 (file)
@@ -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'}} */
+    ;
+  }
+
+}