diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.def | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 52 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 25 | ||||
-rw-r--r-- | clang/test/Sema/function-redecl.c | 28 |
4 files changed, 106 insertions, 1 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.def b/clang/include/clang/Basic/DiagnosticSemaKinds.def index 2016d4ff47c..24bca6a0cf2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.def +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.def @@ -84,6 +84,8 @@ DIAG(err_declarator_need_ident, ERROR, "declarator requires an identifier") DIAG(err_bad_language, ERROR, "unknown linkage language") +DIAG(warn_use_out_of_scope_declaration, WARNING, + "use of out-of-scope declaration of %0") /// Built-in functions. DIAG(ext_implicit_lib_function_decl, EXTWARN, 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; } diff --git a/clang/test/Sema/function-redecl.c b/clang/test/Sema/function-redecl.c index 4be03227227..daa5044dd08 100644 --- a/clang/test/Sema/function-redecl.c +++ b/clang/test/Sema/function-redecl.c @@ -58,3 +58,31 @@ void test2() { } } } + +// <rdar://problem/6127293> +int outer1(int); // expected-note{{previous declaration is here}} +struct outer3 { }; +int outer4(int); +int outer5; // expected-note{{previous definition is here}} +int *outer7(int); + +void outer_test() { + int outer1(float); // expected-error{{conflicting types for 'outer1'}} + int outer2(int); // expected-note{{previous declaration is here}} + int outer3(int); // expected-note{{previous declaration is here}} + int outer4(int); // expected-note{{previous declaration is here}} + int outer5(int); // expected-error{{redefinition of 'outer5' as different kind of symbol}} + int* outer6(int); // expected-note{{previous declaration is here}} + int *outer7(int); + + int *ip7 = outer7(6); +} + +int outer2(float); // expected-error{{conflicting types for 'outer2'}} +int outer3(float); // expected-error{{conflicting types for 'outer3'}} +int outer4(float); // expected-error{{conflicting types for 'outer4'}} + +void outer_test2(int x) { + int* ip = outer6(x); // expected-warning{{use of out-of-scope declaration of 'outer6'}} + int *ip2 = outer7(x); +} |