From 37e876e3dbbb18d37d8824f2d1fee87072e3764c Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 4 Oct 2017 01:49:22 +0000 Subject: [PATCH] PR34822: Fix a collection of related bugs with our handling of C89 implicit function declarations. We were injecting the function into the wrong semantic context, resulting in it failing to be registered as a global for redeclaration lookup. As a consequence, we accepted invalid code since r310616. Fixing that resulted in the "out-of-scope declaration" diagnostic firing a lot more often. It turned out that warning codepath was non-conforming, because it did not cause us to inject the implicitly-declared function into the enclosing block scope. We now only warn if the type of the out-of-scope declaration doesn't match the type of an implicitly-declared function; in all other cases, we produce the normal warning for an implicitly-declared function. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@314871 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 6 ++- lib/Sema/SemaDecl.cpp | 44 ++++++++++++++-------- test/Misc/warning-flags.c | 3 +- test/Sema/implicit-decl-c90.c | 15 +++++++- test/Sema/implicit-decl.c | 4 +- 5 files changed, 49 insertions(+), 23 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 3d20cab8d7..0c491cc60d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -366,8 +366,10 @@ def err_language_linkage_spec_unknown : Error<"unknown linkage language">; def err_language_linkage_spec_not_ascii : Error< "string literal in language linkage specifier cannot have an " "encoding-prefix">; -def warn_use_out_of_scope_declaration : Warning< - "use of out-of-scope declaration of %0">; +def ext_use_out_of_scope_declaration : ExtWarn< + "use of out-of-scope declaration of %0%select{| whose type is not " + "compatible with that of an implicit declaration}1">, + InGroup>; def err_inline_non_function : Error< "'inline' can only appear on functions%select{| and non-local variables}0">; def err_noreturn_non_function : Error< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index fcdc0b39dd..06009b1756 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -12613,14 +12613,32 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D, /// call, forming a call to an implicitly defined function (per C99 6.5.1p2). NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, Scope *S) { + Scope *BlockScope = S; + while (!BlockScope->isCompoundStmtScope() && BlockScope->getParent()) + BlockScope = BlockScope->getParent(); + // 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. - if (NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II)) { - Diag(Loc, diag::warn_use_out_of_scope_declaration) << ExternCPrev; - Diag(ExternCPrev->getLocation(), diag::note_previous_declaration); - return ExternCPrev; + NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II); + if (ExternCPrev) { + // We still need to inject the function into the enclosing block scope so + // that later (non-call) uses can see it. + PushOnScopeChains(ExternCPrev, BlockScope, /*AddToContext*/false); + + // C89 footnote 38: + // If in fact it is not defined as having type "function returning int", + // the behavior is undefined. + if (!isa(ExternCPrev) || + !Context.typesAreCompatible( + cast(ExternCPrev)->getType(), + Context.getFunctionNoProtoType(Context.IntTy))) { + Diag(Loc, diag::ext_use_out_of_scope_declaration) + << ExternCPrev << !getLangOpts().C99; + Diag(ExternCPrev->getLocation(), diag::note_previous_declaration); + return ExternCPrev; + } } // Extension in C99. Legal in C90, but warn about it. @@ -12636,6 +12654,12 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, diag_id = diag::warn_implicit_function_decl; Diag(Loc, diag_id) << &II; + // If we found a prior declaration of this function, don't bother building + // another one. We've already pushed that one into scope, so there's nothing + // more to do. + if (ExternCPrev) + return ExternCPrev; + // Because typo correction is expensive, only do it if the implicit // function declaration is going to be treated as an error. if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) { @@ -12687,19 +12711,9 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, D.SetIdentifier(&II, Loc); // Insert this function into the enclosing block scope. - while (S && !S->isCompoundStmtScope()) - S = S->getParent(); - if (S == nullptr) - S = TUScope; - - DeclContext *PrevDC = CurContext; - CurContext = Context.getTranslationUnitDecl(); - - FunctionDecl *FD = cast(ActOnDeclarator(S, D)); + FunctionDecl *FD = cast(ActOnDeclarator(BlockScope, D)); FD->setImplicit(); - CurContext = PrevDC; - AddKnownFunctionAttributes(FD); return FD; diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c index 5172d3b15a..2c48fa4dbf 100644 --- a/test/Misc/warning-flags.c +++ b/test/Misc/warning-flags.c @@ -18,7 +18,7 @@ This test serves two purposes: The list of warnings below should NEVER grow. It should gradually shrink to 0. -CHECK: Warnings without flags (78): +CHECK: Warnings without flags (77): CHECK-NEXT: ext_excess_initializers CHECK-NEXT: ext_excess_initializers_in_char_array_initializer CHECK-NEXT: ext_expected_semi_decl_list @@ -94,7 +94,6 @@ CHECK-NEXT: warn_typecheck_function_qualifiers CHECK-NEXT: warn_undef_interface CHECK-NEXT: warn_undef_interface_suggest CHECK-NEXT: warn_undef_protocolref -CHECK-NEXT: warn_use_out_of_scope_declaration CHECK-NEXT: warn_weak_identifier_undeclared CHECK-NEXT: warn_weak_import diff --git a/test/Sema/implicit-decl-c90.c b/test/Sema/implicit-decl-c90.c index 38b01759a7..6b3491cff7 100644 --- a/test/Sema/implicit-decl-c90.c +++ b/test/Sema/implicit-decl-c90.c @@ -1,8 +1,9 @@ // RUN: %clang_cc1 %s -std=c90 -verify -fsyntax-only void t0(int x) { + int explicit_decl(); int (*p)(); if(x > 0) - x = g() + 1; + x = g() + 1; // expected-note {{previous implicit declaration}} p = g; if(x < 0) { extern void u(int (*)[h()]); @@ -25,6 +26,8 @@ void t1(int x) { } p = g; /* expected-error {{use of undeclared identifier 'g'}} */ p = h; /* expected-error {{use of undeclared identifier 'h'}} */ + explicit_decl(); + p = explicit_decl; } int t2(int x) { @@ -33,7 +36,15 @@ int t2(int x) { return y; } +int PR34822() { + {int i = sizeof(PR34822_foo());} /* expected-note {{previous definition is here}} */ + {extern int PR34822_foo;} /* expected-error {{redefinition of 'PR34822_foo' as different kind of symbol}} */ + + {extern int PR34822_bar;} /* expected-note {{previous declaration is here}} */ + {int i = sizeof(PR34822_bar());} /* expected-warning {{use of out-of-scope declaration of 'PR34822_bar' whose type is not compatible with that of an implicit declaration}} expected-error {{called object type 'int' is not a function or function pointer}} */ +} + int (*p)() = g; /* expected-error {{use of undeclared identifier 'g'}} */ int (*q)() = h; /* expected-error {{use of undeclared identifier 'h'}} */ -float g(); /* not expecting conflicting types diagnostics here */ +float g(); /* expected-error {{conflicting types for 'g'}} */ diff --git a/test/Sema/implicit-decl.c b/test/Sema/implicit-decl.c index 0a89201078..a04bb0e22e 100644 --- a/test/Sema/implicit-decl.c +++ b/test/Sema/implicit-decl.c @@ -9,7 +9,7 @@ void func() { int32_t *vector[16]; const char compDesc[16 + 1]; int32_t compCount = 0; - if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { // expected-error {{implicit declaration of function '_CFCalendarDecomposeAbsoluteTimeV' is invalid in C99}} + if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { // expected-error {{implicit declaration of function '_CFCalendarDecomposeAbsoluteTimeV' is invalid in C99}} expected-note {{previous implicit declaration}} } printg("Hello, World!\n"); // expected-error{{implicit declaration of function 'printg' is invalid in C99}} \ @@ -17,7 +17,7 @@ void func() { __builtin_is_les(1, 3); // expected-error{{use of unknown builtin '__builtin_is_les'}} } -Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t **vector, int32_t count) { +Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t **vector, int32_t count) { // expected-error {{conflicting types}} return 0; } -- 2.40.0