summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
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