diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 74 |
1 files changed, 40 insertions, 34 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e62834ba1da..418a70a8ba4 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4354,21 +4354,22 @@ TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo, } /// \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 @@ Sema::findLocallyScopedExternCDecl(DeclarationName Name) { 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 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, 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 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, // 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 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // 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 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, 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 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, // 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. |

