summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-02-24 04:26:15 +0000
committerDouglas Gregor <dgregor@apple.com>2009-02-24 04:26:15 +0000
commitde681d43eb42158d76a217e7ed6f26ad5f946d7e (patch)
tree1bc72082bbbca13aaa1f0a7c51747113ebb92289 /clang/lib
parent729a8202d0ba660acdc19ddb96420c3363bf2362 (diff)
downloadbcm5719-llvm-de681d43eb42158d76a217e7ed6f26ad5f946d7e.tar.gz
bcm5719-llvm-de681d43eb42158d76a217e7ed6f26ad5f946d7e.zip
In C, when we see a function declaration within a local scope, export
that declaration to global scope so that it can be found from other scopes. This allows us to diagnose redeclaration errors for external declarations across scopes. We also warn when name lookup finds such an out-of-scope declaration. This is part of <rdar://problem/6127293>; we'll also need to do the same thing for variables. llvm-svn: 65373
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp52
-rw-r--r--clang/lib/Sema/SemaExpr.cpp25
2 files changed, 76 insertions, 1 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 634017330d2..00136badfea 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2033,6 +2033,58 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
InvalidDecl = true;
}
}
+
+ 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;
+ }
+
return NewFD;
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index aef66619f6b..a58752cb42a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -70,12 +70,13 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
}
// See if this is a deleted function.
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isDeleted()) {
Diag(Loc, diag::err_deleted_function_use);
Diag(D->getLocation(), diag::note_unavailable_here) << true;
return true;
}
+ }
// See if the decl is unavailable
if (D->getAttr<UnavailableAttr>()) {
@@ -83,6 +84,28 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
Diag(D->getLocation(), diag::note_unavailable_here) << 0;
}
+ if (D->getDeclContext()->isFunctionOrMethod() &&
+ !D->getDeclContext()->Encloses(CurContext)) {
+ // We've found the name of a function or variable that was
+ // declared with external linkage within another function (and,
+ // therefore, a scope where we wouldn't normally see the
+ // declaration). Once we've made sure that no previous declaration
+ // was properly made visible, produce a warning.
+ bool HasGlobalScopedDeclaration = false;
+ for (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); FD;
+ FD = FD->getPreviousDeclaration()) {
+ if (FD->getDeclContext()->isFileContext()) {
+ HasGlobalScopedDeclaration = true;
+ break;
+ }
+ }
+ // FIXME: do the same thing for variable declarations
+
+ if (!HasGlobalScopedDeclaration) {
+ Diag(Loc, diag::warn_use_out_of_scope_declaration) << D;
+ Diag(D->getLocation(), diag::note_previous_declaration);
+ }
+ }
return false;
}
OpenPOWER on IntegriCloud