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.