aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r--lib/Sema/SemaDecl.cpp264
1 files changed, 161 insertions, 103 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 00136badfe..9ffc680bcb 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1535,10 +1535,137 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
return NewTD;
}
+/// \brief Determines whether the given declaration is an out-of-scope
+/// previous declaration.
+///
+/// This routine should be invoked when name lookup has found a
+/// previous declaration (PrevDecl) that is not in the scope where a
+/// new declaration by the same name is being introduced. If the new
+/// declaration occurs in a local scope, previous declarations with
+/// linkage may still be considered previous declarations (C99
+/// 6.2.2p4-5, C++ [basic.link]p6).
+///
+/// \param PrevDecl the previous declaration found by name
+/// lookup
+///
+/// \param DC the context in which the new declaration is being
+/// declared.
+///
+/// \returns true if PrevDecl is an out-of-scope previous declaration
+/// for a new delcaration with the same name.
+static bool
+isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
+ ASTContext &Context) {
+ if (!PrevDecl)
+ return 0;
+
+ // FIXME: PrevDecl could be an OverloadedFunctionDecl, in which
+ // case we need to check each of the overloaded functions.
+
+ if (Context.getLangOptions().CPlusPlus) {
+ // C++ [basic.link]p6:
+ // If there is a visible declaration of an entity with linkage
+ // having the same name and type, ignoring entities declared
+ // outside the innermost enclosing namespace scope, the block
+ // scope declaration declares that same entity and receives the
+ // linkage of the previous declaration.
+ DeclContext *OuterContext = DC->getLookupContext();
+ if (!OuterContext->isFunctionOrMethod())
+ // This rule only applies to block-scope declarations.
+ return false;
+ else {
+ DeclContext *PrevOuterContext = PrevDecl->getDeclContext();
+ if (PrevOuterContext->isRecord())
+ // We found a member function: ignore it.
+ return false;
+ else {
+ // Find the innermost enclosing namespace for the new and
+ // previous declarations.
+ while (!OuterContext->isFileContext())
+ OuterContext = OuterContext->getParent();
+ while (!PrevOuterContext->isFileContext())
+ PrevOuterContext = PrevOuterContext->getParent();
+
+ // The previous declaration is in a different namespace, so it
+ // isn't the same function.
+ if (OuterContext->getPrimaryContext() !=
+ PrevOuterContext->getPrimaryContext())
+ return false;
+ }
+ }
+ }
+
+ // If the declaration we've found has no linkage, ignore it.
+ if (VarDecl *VD = dyn_cast<VarDecl>(PrevDecl)) {
+ if (!VD->hasGlobalStorage())
+ return false;
+ } else if (!isa<FunctionDecl>(PrevDecl))
+ return false;
+
+ 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,
- Decl* PrevDecl, bool& InvalidDecl,
+ NamedDecl* PrevDecl, bool& InvalidDecl,
bool &Redeclaration) {
DeclarationName Name = GetNameForDeclarator(D);
@@ -1624,9 +1751,18 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Diag(D.getIdentifierLoc(), diag::warn_attribute_weak_on_local);
}
- // Merge the decl with the existing one if appropriate. If the decl is
- // in an outer scope, it isn't the same thing.
- if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) {
+ // If name lookup finds a previous declaration that is not in the
+ // same scope as the new declaration, this may still be an
+ // acceptable redeclaration.
+ if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) &&
+ !((NewVD->hasExternalStorage() ||
+ (NewVD->isFileVarDecl() &&
+ NewVD->getStorageClass() != VarDecl::Static)) &&
+ isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
+ PrevDecl = 0;
+
+ // Merge the decl with the existing one if appropriate.
+ if (PrevDecl) {
if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) {
// The user tried to define a non-static data member
// out-of-line (C++ [dcl.meaning]p1).
@@ -1647,6 +1783,14 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
InvalidDecl = true;
}
}
+
+ // 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->hasExternalStorage())
+ InjectLocallyScopedExternalDeclaration(NewVD);
+
return NewVD;
}
@@ -1858,55 +2002,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
CheckOverloadedOperatorDeclaration(NewFD))
NewFD->setInvalidDecl();
- if (PrevDecl && !isDeclInScope(PrevDecl, DC, S)) {
- // Name lookup has found a previous declaration that is not in the
- // same scope as the new declaration. However, these two
- // declarations might still declare the same thing (C99 6.2.2p3-4,
- // C++ [basic.link]p6).
-
- // FIXME: PrevDecl could be an OverloadedFunctionDecl, in which
- // case we need to check each of the overloaded functions.
-
- if (getLangOptions().CPlusPlus) {
- // C++ [basic.link]p6:
- // If there is a visible declaration of an entity with linkage
- // having the same name and type, ignoring entities declared
- // outside the innermost enclosing namespace scope, the block
- // scope declaration declares that same entity and receives the
- // linkage of the previous declaration.
- DeclContext *OuterContext = DC->getLookupContext();
- if (!OuterContext->isFunctionOrMethod())
- // This rule only applies to block-scope declarations.
- PrevDecl = 0;
- else {
- DeclContext *PrevOuterContext = PrevDecl->getDeclContext();
- if (PrevOuterContext->isRecord())
- // We found a member function: ignore it.
- PrevDecl = 0;
- else {
- // Find the innermost enclosing namespace for the new and
- // previous declarations.
- while (!OuterContext->isFileContext())
- OuterContext = OuterContext->getParent();
- while (!PrevOuterContext->isFileContext())
- PrevOuterContext = PrevOuterContext->getParent();
-
- // The previous declaration is in a different namespace, so it
- // isn't the same function.
- if (OuterContext->getPrimaryContext() !=
- PrevOuterContext->getPrimaryContext())
- PrevDecl = 0;
- }
- }
- }
-
- // If the declaration we've found has no linkage, ignore it.
- if (VarDecl *VD = dyn_cast_or_null<VarDecl>(PrevDecl)) {
- if (!VD->hasGlobalStorage())
- PrevDecl = 0;
- } else if (PrevDecl && !isa<FunctionDecl>(PrevDecl))
- PrevDecl = 0;
- }
+ // If name lookup finds a previous declaration that is not in the
+ // same scope as the new declaration, this may still be an
+ // acceptable redeclaration.
+ if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) &&
+ (isa<CXXMethodDecl>(NewFD) ||
+ NewFD->getStorageClass() == FunctionDecl::Static ||
+ !isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
+ PrevDecl = 0;
// Merge or overload the declaration with an existing declaration of
// the same name, if appropriate.
@@ -2034,56 +2137,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
}
- if (!getLangOptions().CPlusPlus && CurContext->isFunctionOrMethod()) {
- // If this is a function declaration in local scope, inject its
- // name into the top-level scope so that it will be visible to
- // later uses and declarations of the same function, since the
- // function is external.
- // 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.
- IdentifierResolver::iterator I = IdResolver.begin(Name),
- IEnd = IdResolver.end();
- NamedDecl *PrevIdDecl = 0;
- while (I != IEnd && !isa<TranslationUnitDecl>((*I)->getDeclContext())) {
- PrevIdDecl = *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 (PrevIdDecl)
- IdResolver.AddShadowedDecl(NewFD, PrevIdDecl);
- else
- IdResolver.AddDecl(NewFD);
- TUScope->AddDecl(NewFD);
- return NewFD;
- }
-
- 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 (PrevIdDecl)
- IdResolver.AddShadowedDecl(NewFD, PrevIdDecl);
- else
- IdResolver.AddDecl(NewFD);
- TUScope->AddDecl(NewFD);
- } else if (isa<FunctionDecl>(*I) && NewFD->declarationReplaces(*I)) {
- // We found a previous declaration of the same function. Replace
- // that declaration with this one.
- TUScope->RemoveDecl(*I);
- TUScope->AddDecl(NewFD);
- IdResolver.RemoveDecl(*I);
- if (PrevIdDecl)
- IdResolver.AddShadowedDecl(NewFD, PrevIdDecl);
- else
- IdResolver.AddDecl(NewFD);
- }
-
- return NewFD;
- }
+ // 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);
return NewFD;
}