Step #2/N of __label__ support: keep pushing LabelDecl forward,
making them be template instantiated in a more normal way and 
make them handle attributes like other decls.

This fixes the used/unused label handling stuff, making it use
the same infrastructure as other decls.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125771 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 30c9d84..77b4257 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -51,6 +51,7 @@
     void VisitFunctionDecl(FunctionDecl *D);
     void VisitFieldDecl(FieldDecl *D);
     void VisitVarDecl(VarDecl *D);
+    void VisitLabelDecl(LabelDecl *D);
     void VisitParmVarDecl(ParmVarDecl *D);
     void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
     void VisitNamespaceDecl(NamespaceDecl *D);
@@ -537,6 +538,11 @@
   }
 }
 
+void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
+  Out << D->getNameAsString() << ":";
+}
+
+
 void DeclPrinter::VisitVarDecl(VarDecl *D) {
   if (!Policy.SuppressSpecifiers && D->getStorageClass() != SC_None)
     Out << VarDecl::getStorageClassSpecifierString(D->getStorageClass()) << " ";
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 2e7f72f..049267a 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -61,8 +61,7 @@
     // or address of a label taken, but no definition of it.  Label fwd
     // definitions are indicated with a null substmt.
     if (L->getStmt() != 0) {
-      if (!L->isUsed())
-        S.Diag(L->getLocation(), diag::warn_unused_label) << L->getDeclName();
+      S.DiagnoseUnusedDecl(L);
       continue;
     }
     
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index bcec9d4..98555d9 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -629,6 +629,9 @@
   if (D->isUsed() || D->hasAttr<UnusedAttr>())
     return false;
 
+  if (isa<LabelDecl>(D))
+    return true;
+  
   // White-list anything that isn't a local variable.
   if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) ||
       !D->getDeclContext()->isFunctionOrMethod())
@@ -675,12 +678,15 @@
   if (!ShouldDiagnoseUnusedDecl(D))
     return;
   
+  unsigned DiagID;
   if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable())
-    Diag(D->getLocation(), diag::warn_unused_exception_param)
-    << D->getDeclName();
+    DiagID = diag::warn_unused_exception_param;
+  else if (isa<LabelDecl>(D))
+    DiagID = diag::warn_unused_label;
   else
-    Diag(D->getLocation(), diag::warn_unused_variable) 
-    << D->getDeclName();
+    DiagID = diag::warn_unused_variable;
+
+  Diag(D->getLocation(), DiagID) << D->getDeclName();
 }
 
 void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index b0636bc..54e9405 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -921,9 +921,9 @@
   }
 
   if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d) &&
-      !isa<TypeDecl>(d)) {
+      !isa<TypeDecl>(d) && !isa<LabelDecl>(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << Attr.getName() << 2 /*variable and function*/;
+      << Attr.getName() << 14 /*variable, function, labels*/;
     return;
   }
 
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 4bba240..6892424 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -8362,7 +8362,11 @@
   // will be validated and/or cleaned up in ActOnFinishFunctionBody.
   if (TheDecl == 0)
     TheDecl = LabelDecl::Create(Context, CurContext, LabLoc, LabelII);
+  return ActOnAddrLabel(OpLoc, LabLoc, TheDecl);
+}
 
+ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
+                                LabelDecl *TheDecl) {
   TheDecl->setUsed();
   // Create the AST node.  The address of a label always has type 'void*'.
   return Owned(new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl,
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 2b323ef..f31fbe2 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -234,26 +234,7 @@
 StmtResult
 Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
                      SourceLocation ColonLoc, Stmt *SubStmt,
-                     const AttributeList *Attr) {
-  // According to GCC docs, "the only attribute that makes sense after a label
-  // is 'unused'".
-  bool HasUnusedAttr = false;
-  for ( ; Attr; Attr = Attr->getNext()) {
-    if (Attr->getKind() == AttributeList::AT_unused) {
-      HasUnusedAttr = true;
-    } else {
-      Diag(Attr->getLoc(), diag::warn_label_attribute_not_unused);
-      Attr->setInvalid(true);
-    }
-  }
-
-  return ActOnLabelStmt(IdentLoc, II, ColonLoc, SubStmt, HasUnusedAttr);
-}
-
-StmtResult
-Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
-                     SourceLocation ColonLoc, Stmt *SubStmt,
-                     bool HasUnusedAttr) {
+                     AttributeList *Attr) {
   // Look up the record for this label identifier.
   LabelDecl *&TheDecl = getCurFunction()->LabelMap[II];
 
@@ -263,6 +244,16 @@
 
   assert(TheDecl->getIdentifier() == II && "Label mismatch!");
 
+  if (Attr)
+    ProcessDeclAttributeList(CurScope, TheDecl, Attr);
+  
+  return ActOnLabelStmt(IdentLoc, TheDecl, ColonLoc, SubStmt);
+}
+
+StmtResult
+Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
+                     SourceLocation ColonLoc, Stmt *SubStmt) {
+  
   // If the label was multiply defined, reject it now.
   if (TheDecl->getStmt()) {
     Diag(IdentLoc, diag::err_redefinition_of_label) << TheDecl->getDeclName();
@@ -273,9 +264,6 @@
   // Otherwise, things are good.  Fill in the declaration and return it.
   TheDecl->setLocation(IdentLoc);
   
-  // FIXME: Just use Decl ATTRIBUTES!
-  if (HasUnusedAttr)
-    TheDecl->setHasUnusedAttribute();
   LabelStmt *LS = new (Context) LabelStmt(IdentLoc, TheDecl, SubStmt);
   TheDecl->setStmt(LS);
   TheDecl->setLocation(IdentLoc);
@@ -1038,8 +1026,6 @@
 StmtResult
 Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
                     IdentifierInfo *LabelII) {
-  getCurFunction()->setHasBranchIntoScope();
-  
   // Look up the record for this label identifier.
   LabelDecl *&TheDecl = getCurFunction()->LabelMap[LabelII];
 
@@ -1047,6 +1033,13 @@
   if (TheDecl == 0)
     TheDecl = LabelDecl::Create(Context, CurContext, LabelLoc, LabelII);
 
+  return ActOnGotoStmt(GotoLoc, LabelLoc, TheDecl);
+}
+
+StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc,
+                               SourceLocation LabelLoc,
+                               LabelDecl *TheDecl) {
+  getCurFunction()->setHasBranchIntoScope();
   TheDecl->setUsed();
   return Owned(new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc));
 }
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 41e44ad..44f5913 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2168,8 +2168,9 @@
 
 llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> *
 LocalInstantiationScope::findInstantiationOf(const Decl *D) {
-  for (LocalInstantiationScope *Current = this; Current; 
+  for (LocalInstantiationScope *Current = this; Current;
        Current = Current->Outer) {
+
     // Check if we found something within this scope.
     const Decl *CheckD = D;
     do {
@@ -2189,8 +2190,11 @@
     if (!Current->CombineWithOuterScope)
       break;
   }
-  
-  assert(0 && "declaration was not instantiated in this scope!");
+
+  // If we didn't find the decl, then we either have a sema bug, or we have a
+  // forward reference to a label declaration.  Return null to indicate that
+  // we have an uninstantiated label.
+  assert(isa<LabelDecl>(D) && "declaration not instantiated in this scope");
   return 0;
 }
 
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 9197b50..ecb9019 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -101,6 +101,14 @@
 }
 
 Decl *
+TemplateDeclInstantiator::VisitLabelDecl(LabelDecl *D) {
+  LabelDecl *Inst = LabelDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+                                      D->getIdentifier());
+  Owner->addDecl(Inst);
+  return Inst;
+}
+
+Decl *
 TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) {
   assert(false && "Namespaces cannot be instantiated");
   return D;
@@ -2863,13 +2871,24 @@
     typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
     llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found
       = CurrentInstantiationScope->findInstantiationOf(D);
-    assert(Found);
     
-    if (Decl *FD = Found->dyn_cast<Decl *>())
-      return cast<NamedDecl>(FD);
+    if (Found) {
+      if (Decl *FD = Found->dyn_cast<Decl *>())
+        return cast<NamedDecl>(FD);
+      
+      unsigned PackIdx = ArgumentPackSubstitutionIndex;
+      return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]);
+    }
+
+    // If we didn't find the decl, then we must have a label decl that hasn't
+    // been found yet.  Lazily instantiate it and return it now.
+    assert(isa<LabelDecl>(D));
     
-    unsigned PackIdx = ArgumentPackSubstitutionIndex;
-    return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]);
+    Decl *Inst = SubstDecl(D, CurContext, TemplateArgs);
+    assert(Inst && "Failed to instantiate label??");
+    
+    CurrentInstantiationScope->InstantiatedLocal(D, Inst);
+    return cast<LabelDecl>(Inst);
   }
 
   if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 1fc3675..913edaa 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1,15 +1,16 @@
-//===------- TreeTransform.h - Semantic Tree Transformation -----*- C++ -*-===/
+//===------- TreeTransform.h - Semantic Tree Transformation -----*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
-//===----------------------------------------------------------------------===/
+//===----------------------------------------------------------------------===//
 //
 //  This file implements a semantic tree transformation that takes a given
 //  AST and rebuilds it, possibly transforming some nodes in the process.
 //
-//===----------------------------------------------------------------------===/
+//===----------------------------------------------------------------------===//
+
 #ifndef LLVM_CLANG_SEMA_TREETRANSFORM_H
 #define LLVM_CLANG_SEMA_TREETRANSFORM_H
 
@@ -975,11 +976,9 @@
   ///
   /// By default, performs semantic analysis to build the new statement.
   /// Subclasses may override this routine to provide different behavior.
-  StmtResult RebuildLabelStmt(SourceLocation IdentLoc, IdentifierInfo *Id,
-                              SourceLocation ColonLoc, Stmt *SubStmt,
-                              bool HasUnusedAttr) {
-    return SemaRef.ActOnLabelStmt(IdentLoc, Id, ColonLoc, SubStmt,
-                                  HasUnusedAttr);
+  StmtResult RebuildLabelStmt(SourceLocation IdentLoc, LabelDecl *L,
+                              SourceLocation ColonLoc, Stmt *SubStmt) {
+    return SemaRef.ActOnLabelStmt(IdentLoc, L, ColonLoc, SubStmt);
   }
 
   /// \brief Build a new "if" statement.
@@ -987,8 +986,8 @@
   /// By default, performs semantic analysis to build the new statement.
   /// Subclasses may override this routine to provide different behavior.
   StmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond,
-                                 VarDecl *CondVar, Stmt *Then, 
-                                 SourceLocation ElseLoc, Stmt *Else) {
+                           VarDecl *CondVar, Stmt *Then, 
+                           SourceLocation ElseLoc, Stmt *Else) {
     return getSema().ActOnIfStmt(IfLoc, Cond, CondVar, Then, ElseLoc, Else);
   }
 
@@ -997,7 +996,7 @@
   /// By default, performs semantic analysis to build the new statement.
   /// Subclasses may override this routine to provide different behavior.
   StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc,
-                                          Expr *Cond, VarDecl *CondVar) {
+                                    Expr *Cond, VarDecl *CondVar) {
     return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Cond, 
                                             CondVar);
   }
@@ -1007,7 +1006,7 @@
   /// By default, performs semantic analysis to build the new statement.
   /// Subclasses may override this routine to provide different behavior.
   StmtResult RebuildSwitchStmtBody(SourceLocation SwitchLoc,
-                                         Stmt *Switch, Stmt *Body) {
+                                   Stmt *Switch, Stmt *Body) {
     return getSema().ActOnFinishSwitchStmt(SwitchLoc, Switch, Body);
   }
 
@@ -1015,10 +1014,8 @@
   ///
   /// By default, performs semantic analysis to build the new statement.
   /// Subclasses may override this routine to provide different behavior.
-  StmtResult RebuildWhileStmt(SourceLocation WhileLoc,
-                                    Sema::FullExprArg Cond,
-                                    VarDecl *CondVar,
-                                    Stmt *Body) {
+  StmtResult RebuildWhileStmt(SourceLocation WhileLoc, Sema::FullExprArg Cond,
+                              VarDecl *CondVar, Stmt *Body) {
     return getSema().ActOnWhileStmt(WhileLoc, Cond, CondVar, Body);
   }
 
@@ -1051,7 +1048,7 @@
   /// Subclasses may override this routine to provide different behavior.
   StmtResult RebuildGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
                              LabelDecl *Label) {
-    return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label->getIdentifier());
+    return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label);
   }
 
   /// \brief Build a new indirect goto statement.
@@ -1543,7 +1540,7 @@
   /// Subclasses may override this routine to provide different behavior.
   ExprResult RebuildAddrLabelExpr(SourceLocation AmpAmpLoc,
                                   SourceLocation LabelLoc, LabelDecl *Label) {
-    return getSema().ActOnAddrLabel(AmpAmpLoc, LabelLoc,Label->getIdentifier());
+    return getSema().ActOnAddrLabel(AmpAmpLoc, LabelLoc, Label);
   }
 
   /// \brief Build a new GNU statement expression.
@@ -4511,12 +4508,16 @@
   if (SubStmt.isInvalid())
     return StmtError();
 
+  Decl *LD = getDerived().TransformDecl(S->getDecl()->getLocation(),
+                                        S->getDecl());
+  if (!LD)
+    return StmtError();
+  
+  
   // FIXME: Pass the real colon location in.
-  SourceLocation ColonLoc = SemaRef.PP.getLocForEndOfToken(S->getIdentLoc());
   return getDerived().RebuildLabelStmt(S->getIdentLoc(),
-                                       S->getDecl()->getIdentifier(), ColonLoc,
-                                       SubStmt.get(),
-                                       S->getDecl()->hasUnusedAttribute());
+                                       cast<LabelDecl>(LD), SourceLocation(),
+                                       SubStmt.get());
 }
 
 template<typename Derived>
@@ -4755,9 +4756,14 @@
 template<typename Derived>
 StmtResult
 TreeTransform<Derived>::TransformGotoStmt(GotoStmt *S) {
+  Decl *LD = getDerived().TransformDecl(S->getLabel()->getLocation(),
+                                        S->getLabel());
+  if (!LD)
+    return StmtError();
+  
   // Goto statements must always be rebuilt, to resolve the label.
   return getDerived().RebuildGotoStmt(S->getGotoLoc(), S->getLabelLoc(),
-                                      S->getLabel());
+                                      cast<LabelDecl>(LD));
 }
 
 template<typename Derived>
@@ -5798,8 +5804,13 @@
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E) {
+  Decl *LD = getDerived().TransformDecl(E->getLabel()->getLocation(),
+                                        E->getLabel());
+  if (!LD)
+    return ExprError();
+  
   return getDerived().RebuildAddrLabelExpr(E->getAmpAmpLoc(), E->getLabelLoc(),
-                                           E->getLabel());
+                                           cast<LabelDecl>(LD));
 }
 
 template<typename Derived>
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 27e7718..dec15dd 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -725,7 +725,6 @@
 
 void ASTDeclReader::VisitLabelDecl(LabelDecl *D) {
   VisitNamedDecl(D);
-  if (Record[Idx++]) D->setHasUnusedAttribute();
 }
 
 
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index dd43e1a..ce07e13 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -654,7 +654,6 @@
 
 void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) {
   VisitNamedDecl(D);
-  Record.push_back(D->hasUnusedAttribute());
   Code = serialization::DECL_LABEL;
 }