When synthesizing a label declaration based on a goto statement that
cannot yet be resolved, be sure to push the new label declaration into
the right place within the identifier chain. Otherwise, name lookup in
C++ gets confused when searching for names that are lexically closer
than the label. Fixes PR9463.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127623 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Sema/IdentifierResolver.h b/include/clang/Sema/IdentifierResolver.h
index 770f146..33486c2 100644
--- a/include/clang/Sema/IdentifierResolver.h
+++ b/include/clang/Sema/IdentifierResolver.h
@@ -53,6 +53,11 @@
     /// declaration was not found, returns false.
     bool ReplaceDecl(NamedDecl *Old, NamedDecl *New);
 
+    /// \brief Insert the given declaration at the given position in the list.
+    void InsertDecl(DeclsTy::iterator Pos, NamedDecl *D) {
+      Decls.insert(Pos, D);
+    }
+                    
   private:
     DeclsTy Decls;
   };
@@ -166,6 +171,10 @@
   /// (and, therefore, replaced).
   bool ReplaceDecl(NamedDecl *Old, NamedDecl *New);
 
+  /// \brief Insert the given declaration prior to the given iterator
+  /// position
+  void InsertDecl(iterator Pos, NamedDecl *D);
+
   /// \brief Link the declaration into the chain of declarations for
   /// the given identifier.
   ///
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 1085622..fcfc053 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -168,6 +168,39 @@
   IDI->AddDecl(D);
 }
 
+void IdentifierResolver::InsertDecl(iterator Pos, NamedDecl *D) {
+  if (Pos == iterator()) {
+    // Simple case: insert at the beginning of the list (which is the
+    // end of the stored vector).
+    AddDecl(D);
+    return;
+  }
+  
+  DeclarationName Name = D->getDeclName();
+  void *Ptr = Name.getFETokenInfo<void>();
+  
+  if (isDeclPtr(Ptr)) {
+    // There's only one element, and we want to insert before it in the list.
+    // Just create the storage for these identifiers and insert them in the
+    // opposite order we normally would.
+    assert(isDeclPtr(Ptr) && "Not a single declaration!");
+    Name.setFETokenInfo(NULL);
+    IdDeclInfo *IDI = &(*IdDeclInfos)[Name];
+    NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
+    IDI->AddDecl(D);
+    IDI->AddDecl(PrevD);
+    return;
+  }
+
+  // General case: insert the declaration at the appropriate point in the 
+  // list, which already has at least two elements.
+  IdDeclInfo *IDI = toIdDeclInfo(Ptr);
+  if (Pos.isIterator())
+    IDI->InsertDecl(Pos.getIterator(), D);
+  else
+    IDI->InsertDecl(IDI->decls_begin(), D);
+}
+
 /// RemoveDecl - Unlink the decl from its shadowed decl chain.
 /// The decl must already be part of the decl chain.
 void IdentifierResolver::RemoveDecl(NamedDecl *D) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 7c3f726..19d96f2 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -494,7 +494,20 @@
   }
 
   S->AddDecl(D);
-  IdResolver.AddDecl(D);
+  
+  if (isa<LabelDecl>(D) && !cast<LabelDecl>(D)->isGnuLocal()) {
+    // Implicitly-generated labels may end up getting generated in an order that
+    // isn't strictly lexical, which breaks name lookup. Be careful to insert
+    // the label at the appropriate place in the identifier chain.
+    for (I = IdResolver.begin(D->getDeclName()); I != IEnd; ++I) {
+      if ((*I)->getLexicalDeclContext()->Encloses(CurContext))
+        break;
+    }
+    
+    IdResolver.InsertDecl(I, D);
+  } else {
+    IdResolver.AddDecl(D);
+  }
 }
 
 bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S,
diff --git a/test/SemaCXX/goto.cpp b/test/SemaCXX/goto.cpp
new file mode 100644
index 0000000..2db9d97
--- /dev/null
+++ b/test/SemaCXX/goto.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR9463
+double *end;
+void f() {
+  {
+    int end = 0;
+    goto end;
+    end = 1;
+  }
+
+ end:
+  return;
+}
+
+void g() {
+  end = 1; // expected-error{{assigning to 'double *' from incompatible type 'int'}}
+}