diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-03-02 00:19:53 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-03-02 00:19:53 +0000 |
commit | 6393519272ce727f4d26e71bbefb5de712274d0e (patch) | |
tree | 1ebe5d1a23ac06f5fadd2152adff7bf0740dc3f0 /lib/Sema/SemaDecl.cpp | |
parent | 8045ee072879657370cbd97dca46aea45ec44e2d (diff) |
Rework the way we find locally-scoped external declarations when we
need them to evaluate redeclarations or call a function that hasn't
already been declared. We now keep a DenseMap of these locally-scoped
declarations so that they are not visible but can be quickly found,
e.g., when we're looking for previous declarations or before we go
ahead and implicitly declare a function that's being called. Fixes
PR3672.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65792 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 137 |
1 files changed, 69 insertions, 68 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 8764cd9d77..33e3921688 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1355,6 +1355,33 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, return QualType(); } +/// \brief Register the given locally-scoped external C declaration so +/// that it can be found later for redeclarations +void +Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl, + Scope *S) { + assert(ND->getLexicalDeclContext()->isFunctionOrMethod() && + "Decl is not a locally-scoped decl!"); + // Note that we have a locally-scoped external with this name. + LocallyScopedExternalDecls[ND->getDeclName()] = ND; + + if (!PrevDecl) + return; + + // If there was a previous declaration of this variable, it may be + // in our identifier chain. Update the identifier chain with the new + // declaration. + if (IdResolver.ReplaceDecl(PrevDecl, ND)) { + // The previous declaration was found on the identifer resolver + // chain, so remove it from its scope. + while (S && !S->isDeclScope(PrevDecl)) + S = S->getParent(); + + if (S) + S->RemoveDecl(PrevDecl); + } +} + NamedDecl* Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, Decl* LastDeclarator, @@ -1476,63 +1503,6 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, return true; } -/// \brief Inject a locally-scoped declaration with external linkage -/// into the appropriate namespace scope. -/// -/// Given a declaration of an entity with linkage that occurs within a -/// local scope, this routine inject that declaration into top-level -/// scope so that it will be visible for later uses and declarations -/// of the same entity. -void Sema::InjectLocallyScopedExternalDeclaration(ValueDecl *VD) { - // FIXME: We don't do this in C++ because, although we would like - // to get the extra checking that this operation implies, - // the declaration itself is not visible according to C++'s rules. - assert(!getLangOptions().CPlusPlus && - "Can't inject locally-scoped declarations in C++"); - IdentifierResolver::iterator I = IdResolver.begin(VD->getDeclName()), - IEnd = IdResolver.end(); - NamedDecl *PrevDecl = 0; - while (I != IEnd && !isa<TranslationUnitDecl>((*I)->getDeclContext())) { - PrevDecl = *I; - ++I; - } - - if (I == IEnd) { - // No name with this identifier has been declared at translation - // unit scope. Add this name into the appropriate scope. - if (PrevDecl) - IdResolver.AddShadowedDecl(VD, PrevDecl); - else - IdResolver.AddDecl(VD); - TUScope->AddDecl(VD); - return; - } - - if (isa<TagDecl>(*I)) { - // The first thing we found was a tag declaration, so insert - // this function so that it will be found before the tag - // declaration. - if (PrevDecl) - IdResolver.AddShadowedDecl(VD, PrevDecl); - else - IdResolver.AddDecl(VD); - TUScope->AddDecl(VD); - return; - } - - if (VD->declarationReplaces(*I)) { - // We found a previous declaration of the same entity. Replace - // that declaration with this one. - TUScope->RemoveDecl(*I); - TUScope->AddDecl(VD); - IdResolver.RemoveDecl(*I); - if (PrevDecl) - IdResolver.AddShadowedDecl(VD, PrevDecl); - else - IdResolver.AddDecl(VD); - } -} - NamedDecl* Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, Decl* LastDeclarator, @@ -1666,6 +1636,16 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, isOutOfScopePreviousDeclaration(PrevDecl, DC, Context))) PrevDecl = 0; + if (!PrevDecl && NewVD->isExternC(Context)) { + // Since we did not find anything by this name and we're declaring + // an extern "C" variable, look for a non-visible extern "C" + // declaration with the same name. + llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos + = LocallyScopedExternalDecls.find(Name); + if (Pos != LocallyScopedExternalDecls.end()) + PrevDecl = Pos->second; + } + // Merge the decl with the existing one if appropriate. if (PrevDecl) { if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) { @@ -1689,12 +1669,11 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } - // If this is a locally-scoped extern variable in C, inject a - // declaration into translation unit scope so that all external - // declarations are visible. - if (!getLangOptions().CPlusPlus && CurContext->isFunctionOrMethod() && - NewVD->hasLinkage()) - InjectLocallyScopedExternalDeclaration(NewVD); + // If this is a locally-scoped extern C variable, update the map of + // such variables. + if (CurContext->isFunctionOrMethod() && NewVD->isExternC(Context) && + !InvalidDecl) + RegisterLocallyScopedExternCDecl(NewVD, PrevDecl, S); return NewVD; } @@ -1920,6 +1899,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isOutOfScopePreviousDeclaration(PrevDecl, DC, Context))) PrevDecl = 0; + if (!PrevDecl && NewFD->isExternC(Context)) { + // Since we did not find anything by this name and we're declaring + // an extern "C" function, look for a non-visible extern "C" + // declaration with the same name. + llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos + = LocallyScopedExternalDecls.find(Name); + if (Pos != LocallyScopedExternalDecls.end()) + PrevDecl = Pos->second; + } + // Merge or overload the declaration with an existing declaration of // the same name, if appropriate. bool OverloadableAttrRequired = false; @@ -2046,11 +2035,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } - // If this is a locally-scoped function in C, inject a declaration - // into translation unit scope so that all external declarations are - // visible. - if (!getLangOptions().CPlusPlus && CurContext->isFunctionOrMethod()) - InjectLocallyScopedExternalDeclaration(NewFD); + // If this is a locally-scoped extern C function, update the + // map of such names. + if (CurContext->isFunctionOrMethod() && NewFD->isExternC(Context) + && !InvalidDecl) + RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S); return NewFD; } @@ -2653,6 +2642,18 @@ Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtArg BodyArg) { /// call, forming a call to an implicitly defined function (per C99 6.5.1p2). NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, Scope *S) { + // Before we produce a declaration for an implicitly defined + // 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 + = LocallyScopedExternalDecls.find(&II); + if (Pos != LocallyScopedExternalDecls.end()) { + Diag(Loc, diag::warn_use_out_of_scope_declaration) << Pos->second; + Diag(Pos->second->getLocation(), diag::note_previous_declaration); + return Pos->second; + } + // Extension in C99. Legal in C90, but warn about it. if (getLangOptions().C99) Diag(Loc, diag::ext_implicit_function_decl) << &II; |