DR14, DR101, and part of DR1: fix handling of extern "C" declarations in
namespaces, by treating them just like we treat extern "C" declarations in
function scope.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184223 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index e62834b..418a70a 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4354,21 +4354,22 @@
 }
 
 /// \brief Register the given locally-scoped extern "C" declaration so
-/// that it can be found later for redeclarations
+/// that it can be found later for redeclarations. We include any extern "C"
+/// declaration that is not visible in the translation unit here, not just
+/// function-scope declarations.
 void
-Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND,
-                                       const LookupResult &Previous,
-                                       Scope *S) {
-  assert(ND->getLexicalDeclContext()->isFunctionOrMethod() &&
-         "Decl is not a locally-scoped decl!");
+Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S) {
+  assert(
+      !ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnit() &&
+      "Decl is not a locally-scoped decl!");
   // Note that we have a locally-scoped external with this name.
   LocallyScopedExternCDecls[ND->getDeclName()] = ND;
 }
 
-llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
-Sema::findLocallyScopedExternCDecl(DeclarationName Name) {
+NamedDecl *Sema::findLocallyScopedExternCDecl(DeclarationName Name) {
   if (ExternalSource) {
     // Load locally-scoped external decls from the external source.
+    // FIXME: This is inefficient. Maybe add a DeclContext for extern "C" decls?
     SmallVector<NamedDecl *, 4> Decls;
     ExternalSource->ReadLocallyScopedExternCDecls(Decls);
     for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
@@ -4378,8 +4379,9 @@
         LocallyScopedExternCDecls[Decls[I]->getDeclName()] = Decls[I];
     }
   }
-  
-  return LocallyScopedExternCDecls.find(Name);
+
+  NamedDecl *D = LocallyScopedExternCDecls.lookup(Name);
+  return D ? cast<NamedDecl>(D->getMostRecentDecl()) : 0;
 }
 
 /// \brief Diagnose function specifiers on a declaration of an identifier that
@@ -5048,11 +5050,17 @@
   ProcessPragmaWeak(S, NewVD);
   checkAttributesAfterMerging(*this, *NewVD);
 
-  // If this is a locally-scoped extern C variable, update the map of
-  // such variables.
-  if (CurContext->isFunctionOrMethod() && NewVD->isExternC() &&
-      !NewVD->isInvalidDecl())
-    RegisterLocallyScopedExternCDecl(NewVD, Previous, S);
+  // If this is the first declaration of an extern C variable that is not
+  // declared directly in the translation unit, update the map of such
+  // variables.
+  if (!CurContext->getRedeclContext()->isTranslationUnit() &&
+      !NewVD->getPreviousDecl() && !NewVD->isInvalidDecl() &&
+      // FIXME: We only check isExternC if we're in an extern C context,
+      // to avoid computing and caching an 'externally visible' flag which
+      // could change if the variable's type is not visible.
+      (!getLangOpts().CPlusPlus || NewVD->isInExternCContext()) &&
+      NewVD->isExternC())
+    RegisterLocallyScopedExternCDecl(NewVD, S);
 
   return NewVD;
 }
@@ -5360,10 +5368,9 @@
   // not in scope.
   bool PreviousWasHidden = false;
   if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) {
-    llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
-      = findLocallyScopedExternCDecl(NewVD->getDeclName());
-    if (Pos != LocallyScopedExternCDecls.end()) {
-      Previous.addDecl(Pos->second);
+    if (NamedDecl *ExternCPrev =
+            findLocallyScopedExternCDecl(NewVD->getDeclName())) {
+      Previous.addDecl(ExternCPrev);
       PreviousWasHidden = true;
     }
   }
@@ -6598,11 +6605,13 @@
   // marking the function.
   AddCFAuditedAttribute(NewFD);
 
-  // If this is a locally-scoped extern C function, update the
-  // map of such names.
-  if (CurContext->isFunctionOrMethod() && NewFD->isExternC()
-      && !NewFD->isInvalidDecl())
-    RegisterLocallyScopedExternCDecl(NewFD, Previous, S);
+  // If this is the first declaration of an extern C variable that is not
+  // declared directly in the translation unit, update the map of such
+  // variables.
+  if (!CurContext->getRedeclContext()->isTranslationUnit() &&
+      !NewFD->getPreviousDecl() && NewFD->isExternC() &&
+      !NewFD->isInvalidDecl())
+    RegisterLocallyScopedExternCDecl(NewFD, S);
 
   // Set this FunctionDecl's range up to the right paren.
   NewFD->setRangeEnd(D.getSourceRange().getEnd());
@@ -6709,10 +6718,9 @@
   if (Previous.empty() && mayConflictWithNonVisibleExternC(NewFD)) {
     // Since we did not find anything by this name, look for a non-visible
     // extern "C" declaration with the same name.
-    llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
-      = findLocallyScopedExternCDecl(NewFD->getDeclName());
-    if (Pos != LocallyScopedExternCDecls.end())
-      Previous.addDecl(Pos->second);
+    if (NamedDecl *ExternCPrev =
+            findLocallyScopedExternCDecl(NewFD->getDeclName()))
+      Previous.addDecl(ExternCPrev);
   }
 
   // Filter out any non-conflicting previous declarations.
@@ -9063,12 +9071,10 @@
   // function, see whether there was a locally-scoped declaration of
   // this name as a function or variable. If so, use that
   // (non-visible) declaration, and complain about it.
-  llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
-    = findLocallyScopedExternCDecl(&II);
-  if (Pos != LocallyScopedExternCDecls.end()) {
-    Diag(Loc, diag::warn_use_out_of_scope_declaration) << Pos->second;
-    Diag(Pos->second->getLocation(), diag::note_previous_declaration);
-    return Pos->second;
+  if (NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II)) {
+    Diag(Loc, diag::warn_use_out_of_scope_declaration) << ExternCPrev;
+    Diag(ExternCPrev->getLocation(), diag::note_previous_declaration);
+    return ExternCPrev;
   }
 
   // Extension in C99.  Legal in C90, but warn about it.