r314871 - PR34822: Fix a collection of related bugs with our handling of C89 implicit function declarations.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 3 18:49:22 PDT 2017


Author: rsmith
Date: Tue Oct  3 18:49:22 2017
New Revision: 314871

URL: http://llvm.org/viewvc/llvm-project?rev=314871&view=rev
Log:
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.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/Misc/warning-flags.c
    cfe/trunk/test/Sema/implicit-decl-c90.c
    cfe/trunk/test/Sema/implicit-decl.c

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=314871&r1=314870&r2=314871&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Oct  3 18:49:22 2017
@@ -366,8 +366,10 @@ def err_language_linkage_spec_unknown :
 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<DiagGroup<"out-of-scope-function">>;
 def err_inline_non_function : Error<
   "'inline' can only appear on functions%select{| and non-local variables}0">;
 def err_noreturn_non_function : Error<

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=314871&r1=314870&r2=314871&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Oct  3 18:49:22 2017
@@ -12613,14 +12613,32 @@ void Sema::ActOnFinishDelayedAttribute(S
 /// 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<FunctionDecl>(ExternCPrev) ||
+        !Context.typesAreCompatible(
+            cast<FunctionDecl>(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::ImplicitlyDefineFunctio
     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::ImplicitlyDefineFunctio
   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<FunctionDecl>(ActOnDeclarator(S, D));
+  FunctionDecl *FD = cast<FunctionDecl>(ActOnDeclarator(BlockScope, D));
   FD->setImplicit();
 
-  CurContext = PrevDC;
-
   AddKnownFunctionAttributes(FD);
 
   return FD;

Modified: cfe/trunk/test/Misc/warning-flags.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/warning-flags.c?rev=314871&r1=314870&r2=314871&view=diff
==============================================================================
--- cfe/trunk/test/Misc/warning-flags.c (original)
+++ cfe/trunk/test/Misc/warning-flags.c Tue Oct  3 18:49:22 2017
@@ -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_qu
 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
 

Modified: cfe/trunk/test/Sema/implicit-decl-c90.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/implicit-decl-c90.c?rev=314871&r1=314870&r2=314871&view=diff
==============================================================================
--- cfe/trunk/test/Sema/implicit-decl-c90.c (original)
+++ cfe/trunk/test/Sema/implicit-decl-c90.c Tue Oct  3 18:49:22 2017
@@ -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'}} */

Modified: cfe/trunk/test/Sema/implicit-decl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/implicit-decl.c?rev=314871&r1=314870&r2=314871&view=diff
==============================================================================
--- cfe/trunk/test/Sema/implicit-decl.c (original)
+++ cfe/trunk/test/Sema/implicit-decl.c Tue Oct  3 18:49:22 2017
@@ -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;
 }
 




More information about the cfe-commits mailing list