diff mbox

Rewrite check_global_declarations() generically

Message ID 55402D60.7020103@redhat.com
State New
Headers show

Commit Message

Aldy Hernandez April 29, 2015, 1:01 a.m. UTC
[This is actually for the debug-early branch, but I figured I'd avoid 
the [debug-early] subject line to alert others of the upcoming change. 
Actually, I should've adapted this and submitted it to mainline, but 
considering I should be submitting the debug-early work "Real Soon Now" 
(tm), I don't want to get side-tracked.]

This is one of those changes that Richi likes-- moving stuff out of the 
front-ends and into generic land...

The check_global_declarations checks were failing in the branch because 
mainline depends on both, trees being present, and tree bits being set 
late in the compilation, sometimes as late as RTL (in the case of 
TREE_SYMBOL_REFERENCED).  The front-ends were making a list of 
interesting globals, and feeding them to check_global_declarations() to 
issue certain use without define (and vice versa) warnings.

Instead of caching these globals from the front-end all the way to the 
back-end, I redesigned it to check global declarations generically, in a 
language agnostic way, while using symtab/cgraph to determine usage 
(instead of TREE_USED and other magic bits that weren't as accurate or 
in certain cases, available).

With this patch we fix a slew of regressions on the debug-early branch, 
and we find a lot more legitimate warnings.  I had to adjust a lot of 
tests, because we're being much more aggressive.  IMO, this is good. 
Interestingly enough, I even found the following in gengtype.c:

+/* ?? Why are we keeping this?  Is this actually used anywhere?  */
+static void ATTRIBUTE_UNUSED
  output_typename (outf_p of, const_type_p t)

The reason mainline was not picking this up was because 
output_typename() was calling itself, thus the infrastructure assumed it 
was used.  By the way, can I remove this unused symbol instead of 
papering over the problem with ATTRIBUTE_UNUSED?

The attached patch was tested with GCC and GDB.  It only has one 
regression, which I've asked Jason to look at to determine if it is a 
false positive or not: g++.dg/torture/pr46383.C.

Gentlemen, is this an approach you can bless?  Don't worry about fully 
reviewing it (unless you want to-- no complaints here), I just want to 
make sure it's something I can commit to the branch and continue onto 
other regressions.  You will all get a chance to crucify the entire 
branch real soon :).

Thanks.
Aldy
commit 9429021847345e95ac8fec2b84affebdf5183a64
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Tue Apr 28 17:34:48 2015 -0700

    Adjust global declaration warnings to work in a language agnostic way
    and use the symbol table infrastructure.

Comments

Jason Merrill April 29, 2015, 7:33 p.m. UTC | #1
On 04/28/2015 09:01 PM, Aldy Hernandez wrote:

The approach looks good to me.

> -  analyze_functions ();
> +  analyze_functions (true);

In the C++ front end at least we comment anonymous boolean arguments, i.e.

  analyze_functions (/*first_time*/true);

Let's do that here, too.  Similarly for the calls to referred_to_p (false).

> +      /* ?? Why are we looking at TREE_USED?  Shouldn't the call to
> +	 referred_to_p above be enough?  Apparently not, because the
> +	 `__unused__' attribute is not being considered for
> +	 referred_to_p.  */

Seems like you answered your question.  :)

> +      /* Global ctors and dtors are called by the runtime.  */
> +      && (TREE_CODE (decl) != FUNCTION_DECL
> +	  || (!DECL_STATIC_CONSTRUCTOR (decl)
> +	      && !DECL_STATIC_DESTRUCTOR (decl)))

Maybe check snode->needed_p instead?

Jason
Richard Biener April 30, 2015, 8:43 a.m. UTC | #2
On Wed, Apr 29, 2015 at 3:01 AM, Aldy Hernandez <aldyh@redhat.com> wrote:
> [This is actually for the debug-early branch, but I figured I'd avoid the
> [debug-early] subject line to alert others of the upcoming change. Actually,
> I should've adapted this and submitted it to mainline, but considering I
> should be submitting the debug-early work "Real Soon Now" (tm), I don't want
> to get side-tracked.]
>
> This is one of those changes that Richi likes-- moving stuff out of the
> front-ends and into generic land...
>
> The check_global_declarations checks were failing in the branch because
> mainline depends on both, trees being present, and tree bits being set late
> in the compilation, sometimes as late as RTL (in the case of
> TREE_SYMBOL_REFERENCED).  The front-ends were making a list of interesting
> globals, and feeding them to check_global_declarations() to issue certain
> use without define (and vice versa) warnings.
>
> Instead of caching these globals from the front-end all the way to the
> back-end, I redesigned it to check global declarations generically, in a
> language agnostic way, while using symtab/cgraph to determine usage (instead
> of TREE_USED and other magic bits that weren't as accurate or in certain
> cases, available).
>
> With this patch we fix a slew of regressions on the debug-early branch, and
> we find a lot more legitimate warnings.  I had to adjust a lot of tests,
> because we're being much more aggressive.  IMO, this is good. Interestingly
> enough, I even found the following in gengtype.c:
>
> +/* ?? Why are we keeping this?  Is this actually used anywhere?  */
> +static void ATTRIBUTE_UNUSED
>  output_typename (outf_p of, const_type_p t)
>
> The reason mainline was not picking this up was because output_typename()
> was calling itself, thus the infrastructure assumed it was used.  By the
> way, can I remove this unused symbol instead of papering over the problem
> with ATTRIBUTE_UNUSED?
>
> The attached patch was tested with GCC and GDB.  It only has one regression,
> which I've asked Jason to look at to determine if it is a false positive or
> not: g++.dg/torture/pr46383.C.
>
> Gentlemen, is this an approach you can bless?  Don't worry about fully
> reviewing it (unless you want to-- no complaints here), I just want to make
> sure it's something I can commit to the branch and continue onto other
> regressions.  You will all get a chance to crucify the entire branch real
> soon :).

Yeah, the approach looks sane.

Richard.

> Thanks.
> Aldy
diff mbox

Patch

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 688c055..34d4ff4 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -10686,7 +10686,7 @@  c_write_global_declarations_1 (tree globals)
     {
       /* Check for used but undefined static functions using the C
 	 standard's definition of "used", and set TREE_NO_WARNING so
-	 that check_global_declarations doesn't repeat the check.  */
+	 that check_global_declaration doesn't repeat the check.  */
       if (TREE_CODE (decl) == FUNCTION_DECL
 	  && DECL_INITIAL (decl) == 0
 	  && DECL_EXTERNAL (decl)
@@ -10707,9 +10707,6 @@  c_write_global_declarations_1 (tree globals)
 	reconsider |= wrapup_global_declaration_2 (decl);
     }
   while (reconsider);
-
-  for (decl = globals; decl; decl = DECL_CHAIN (decl))
-    check_global_declaration_1 (decl);
 }
 
 /* Callback to collect a source_ref from a DECL.  */
@@ -10811,7 +10808,7 @@  c_parse_final_cleanups (void)
     }
 
   /* Process all file scopes in this compilation, and the external_scope,
-     through wrapup_global_declarations and check_global_declarations.  */
+     through wrapup_global_declarations.  */
   FOR_EACH_VEC_ELT (*all_translation_units, i, t)
     c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
   c_write_global_declarations_1 (BLOCK_VARS (ext_block));
diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c
index 344d4e2..7fcb7fd 100644
--- a/gcc/c/c-objc-common.c
+++ b/gcc/c/c-objc-common.c
@@ -51,7 +51,7 @@  c_missing_noreturn_ok_p (tree decl)
   return flag_hosted && MAIN_NAME_P (DECL_ASSEMBLER_NAME (decl));
 }
 
-/* Called from check_global_declarations.  */
+/* Called from check_global_declaration.  */
 
 bool
 c_warn_unused_global_decl (const_tree decl)
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 29f65a8..fc8bff7 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -314,7 +314,7 @@  public:
   bool needed_p (void);
 
   /* Return true when there are references to the node.  */
-  bool referred_to_p (void);
+  bool referred_to_p (bool include_self = true);
 
   /* Return true if NODE can be discarded by linker from the binary.  */
   inline bool
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 418c49f..0ee1d2b 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -406,10 +406,11 @@  cgraph_node::reset (void)
   remove_all_references ();
 }
 
-/* Return true when there are references to the node.  */
+/* Return true when there are references to the node.  INCLUDE_SELF is
+   true if a self reference counts as a reference.  */
 
 bool
-symtab_node::referred_to_p (void)
+symtab_node::referred_to_p (bool include_self)
 {
   ipa_ref *ref = NULL;
 
@@ -419,7 +420,13 @@  symtab_node::referred_to_p (void)
   /* For functions check also calls.  */
   cgraph_node *cn = dyn_cast <cgraph_node *> (this);
   if (cn && cn->callers)
-    return true;
+    {
+      if (include_self)
+	return true;
+      for (cgraph_edge *e = cn->callers; e; e = e->next_caller)
+	if (e->caller != this)
+	  return true;
+    }
   return false;
 }
 
@@ -928,8 +935,12 @@  walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
 static cgraph_node *first_analyzed;
 static varpool_node *first_analyzed_var;
 
+/* FIRST_TIME is set to TRUE for the first time we are called for a
+   translation unit from finalize_compilation_unit() or false
+   otherwise.  */
+
 static void
-analyze_functions (void)
+analyze_functions (bool first_time)
 {
   /* Keep track of already processed nodes when called multiple times for
      intermodule optimization.  */
@@ -1101,6 +1112,13 @@  analyze_functions (void)
       symtab_node::dump_table (symtab->dump_file);
     }
 
+  if (first_time)
+    {
+      symtab_node *snode;
+      FOR_EACH_SYMBOL (snode)
+	check_global_declaration (snode->decl);
+    }
+
   if (symtab->dump_file)
     fprintf (symtab->dump_file, "\nRemoving unused symbols:");
 
@@ -2449,13 +2467,13 @@  symbol_table::finalize_compilation_unit (void)
 
   /* Gimplify and lower all functions, compute reachability and
      remove unreachable nodes.  */
-  analyze_functions ();
+  analyze_functions (true);
 
   /* Mark alias targets necessary and emit diagnostics.  */
   handle_alias_pairs ();
 
   /* Gimplify and lower thunks.  */
-  analyze_functions ();
+  analyze_functions (false);
 
   /* Emit early debug for reachable functions, and by consequence,
      locally scoped symbols.  */
diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index dd8e7c5..40b13ef 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -60,7 +60,7 @@  cxx_get_alias_set (tree t)
   return c_common_get_alias_set (t);
 }
 
-/* Called from check_global_declarations.  */
+/* Called from check_global_declaration.  */
 
 bool
 cxx_warn_unused_global_decl (const_tree decl)
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index c67dc19..da21475 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4359,21 +4359,6 @@  dump_tu (void)
     }
 }
 
-/* Issue warnings for globals in NAME_SPACE (unused statics, etc).  */
-
-static int
-check_statics_for_namespace (tree name_space, void* data ATTRIBUTE_UNUSED)
-{
-  cp_binding_level *level = NAMESPACE_LEVEL (name_space);
-  vec<tree, va_gc> *statics = level->static_decls;
-  tree *vec = statics->address ();
-  int len = statics->length ();
-
-  check_global_declarations (vec, len);
-
-  return 0;
-}
-
 static location_t locus_at_end_of_parsing;
 
 /* Check the deallocation functions for CODE to see if we want to warn that
@@ -4739,7 +4724,7 @@  c_parse_final_cleanups (void)
 				(template_for_substitution (decl)))))
 	{
 	  warning (0, "inline function %q+D used but never defined", decl);
-	  /* Avoid a duplicate warning from check_global_declaration_1.  */
+	  /* Avoid a duplicate warning from check_global_declaration.  */
 	  TREE_NO_WARNING (decl) = 1;
 	}
     }
@@ -4802,10 +4787,6 @@  c_parse_final_cleanups (void)
      generate initial debug information.  */
   timevar_stop (TV_PHASE_PARSING);
   timevar_start (TV_PHASE_DBGINFO);
-  walk_namespaces (check_statics_for_namespace, 0);
-  if (vec_safe_length (pending_statics) != 0)
-    check_global_declarations (pending_statics->address (),
-			       pending_statics->length ());
 
   perform_deferred_noexcept_checks ();
 
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 02012d5..15b6dd2 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -4718,7 +4718,8 @@  write_roots (pair_p variables, bool emit_pch)
    this funcion will have to be adjusted to be more like
    output_mangled_typename.  */
 
-static void
+/* ?? Why are we keeping this?  Is this actually used anywhere?  */
+static void ATTRIBUTE_UNUSED
 output_typename (outf_p of, const_type_p t)
 {
   switch (t->kind)
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 7965b11..1f7882e 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -3084,8 +3084,6 @@  Gcc_backend::write_global_definitions(
 
   wrapup_global_declarations(defs, i);
 
-  check_global_declarations(defs, i);
-
   delete[] defs;
 }
 
diff --git a/gcc/langhooks.c b/gcc/langhooks.c
index c900f26..84058b1 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -139,12 +139,12 @@  lhd_print_tree_nothing (FILE * ARG_UNUSED (file),
 {
 }
 
-/* Called from check_global_declarations.  */
+/* Called from check_global_declaration.  */
 
 bool
 lhd_warn_unused_global_decl (const_tree decl)
 {
-  /* This is what used to exist in check_global_declarations.  Probably
+  /* This is what used to exist in check_global_declaration.  Probably
      not many of these actually apply to non-C languages.  */
 
   if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl))
@@ -338,7 +338,6 @@  global_decl_processing (void)
     vec[len - i - 1] = decl;
 
   wrapup_global_declarations (vec, len);
-  check_global_declarations (vec, len);
   timevar_stop (TV_PHASE_DEFERRED);
 
   timevar_start (TV_PHASE_PARSING);
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr57101.C b/gcc/testsuite/g++.dg/cpp0x/pr57101.C
index c0fc966..1db444e 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr57101.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr57101.C
@@ -160,7 +160,7 @@  namespace std
     typedef _Alloc allocator_type;
     template < typename _Key_compare > struct _Rb_tree_impl
     {
-      _Rb_tree_impl (_Key_compare, _Node_allocator);
+      _Rb_tree_impl (_Key_compare, _Node_allocator); // { dg-warning "used but never defined" }
     };
     _Rb_tree_impl < _Compare > _M_impl;
   _Rb_tree (_Compare __comp, allocator_type __a):
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/dwarf4-typedef.C b/gcc/testsuite/g++.dg/debug/dwarf2/dwarf4-typedef.C
index 89a6bb4..cd1a0af 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/dwarf4-typedef.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/dwarf4-typedef.C
@@ -6,7 +6,7 @@ 
 namespace {
 
 struct A {
-  virtual ~A();
+  virtual ~A(); // { dg-warning "used but never defined" }
 };
 
 struct B : public A {
diff --git a/gcc/testsuite/g++.dg/ext/visibility/anon7.C b/gcc/testsuite/g++.dg/ext/visibility/anon7.C
index 0c42ea8..1aa239e 100644
--- a/gcc/testsuite/g++.dg/ext/visibility/anon7.C
+++ b/gcc/testsuite/g++.dg/ext/visibility/anon7.C
@@ -4,7 +4,7 @@ 
 namespace
 {
   struct A {
-    static int bar ();
+    static int bar ();		// { dg-error "used but never defined" "" }
     static int i;		// { dg-error "used, but not defined" "" { xfail *-*-* } }
     static int j;
     static int k;
diff --git a/gcc/testsuite/g++.dg/ipa/pr63587-2.C b/gcc/testsuite/g++.dg/ipa/pr63587-2.C
index f31c5bd..a15f17e 100644
--- a/gcc/testsuite/g++.dg/ipa/pr63587-2.C
+++ b/gcc/testsuite/g++.dg/ipa/pr63587-2.C
@@ -178,7 +178,7 @@  public:
   }
 };
 template <typename AttributeValueT>
-attribute_actor<AttributeValueT> attr (attribute_name);
+attribute_actor<AttributeValueT> attr (attribute_name); // { dg-warning "used but never defined" }
 terminal<>::type stream;
 template <typename LeftT, typename ImplT> class attribute_output_terminal
 {
diff --git a/gcc/testsuite/g++.dg/opt/dump1.C b/gcc/testsuite/g++.dg/opt/dump1.C
index d263f18..f74d024 100644
--- a/gcc/testsuite/g++.dg/opt/dump1.C
+++ b/gcc/testsuite/g++.dg/opt/dump1.C
@@ -311,7 +311,7 @@  namespace std __attribute__ ((__visibility__ ("default")))
     typename __add_ref<
                       typename tuple_element<__i, tuple<_Elements...>>::type
                     >::type
-    get(tuple<_Elements...>& __t) noexcept;
+    get(tuple<_Elements...>& __t) noexcept; // { dg-warning "used but never defined" }
   template<std::size_t... _Indexes>
     struct _Index_tuple
     {};
@@ -386,7 +386,7 @@  namespace std __attribute__ ((__visibility__ ("default")))
     };
   template<typename _Callable, typename... _Args>
     typename _Bind_simple_helper<_Callable, _Args...>::__type
-    __bind_simple(_Callable&& __callable, _Args&&... __args)
+    __bind_simple(_Callable&& __callable, _Args&&... __args)  // { dg-warning "used but never defined" }
   ;
   union _Any_data
   ;
@@ -403,7 +403,7 @@  namespace std __attribute__ ((__visibility__ ("default")))
       {
       protected:
  static _Functor*
- _M_get_pointer(const _Any_data& __source)
+ _M_get_pointer(const _Any_data& __source)  // { dg-warning "used but never defined" }
  ;
       };
   };
@@ -510,7 +510,7 @@  namespace std __attribute__ ((__visibility__ ("default")))
         _S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
  { ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); }
       static pointer
-      allocate(_Alloc& __a, size_type __n)
+      allocate(_Alloc& __a, size_type __n)  // { dg-warning "used but never defined" }
       ;
       template<typename _Tp, typename... _Args>
  static auto construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
diff --git a/gcc/testsuite/g++.dg/opt/pr59622-3.C b/gcc/testsuite/g++.dg/opt/pr59622-3.C
index 0af8605..94d66aa 100644
--- a/gcc/testsuite/g++.dg/opt/pr59622-3.C
+++ b/gcc/testsuite/g++.dg/opt/pr59622-3.C
@@ -8,7 +8,7 @@  namespace
 {
   struct A
   {
-    virtual C foo ();
+    virtual C foo (); // { dg-warning "used but never defined" }
     C bar () { return foo (); }
   };
 }
diff --git a/gcc/testsuite/g++.dg/opt/pr59622.C b/gcc/testsuite/g++.dg/opt/pr59622.C
index 1d8e998..f62cf41 100644
--- a/gcc/testsuite/g++.dg/opt/pr59622.C
+++ b/gcc/testsuite/g++.dg/opt/pr59622.C
@@ -6,7 +6,7 @@  namespace
 {
   struct A
   {
-    virtual int foo ();
+    virtual int foo (); // { dg-warning "used but never defined" }
     int bar () { return foo (); }
   };
 }
diff --git a/gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-8.c b/gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-8.c
index 39d38c1..a54c900 100644
--- a/gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-8.c
+++ b/gcc/testsuite/gcc.dg/dfp/pragma-float-const-decimal64-8.c
@@ -145,7 +145,7 @@  here:
 double
 f10 (void)
 {
-  void foo10 (void)
+  void foo10 (void) /* { dg-warning "defined but not used" } */
   {
     a = 1.0;
   }
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 5e3bd08..43e1577 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -500,15 +500,15 @@  wrapup_global_declarations (tree *vec, int len)
   return output_something;
 }
 
-/* A subroutine of check_global_declarations.  Issue appropriate warnings
-   for the global declaration DECL.  */
+/* Issue appropriate warnings for the global declaration DECL.  */
 
 void
-check_global_declaration_1 (tree decl)
+check_global_declaration (tree decl)
 {
   /* Warn about any function declared static but not defined.  We don't
      warn about variables, because many programs have static variables
      that exist only to get some text into the object file.  */
+  symtab_node *snode = symtab_node::get (decl);
   if (TREE_CODE (decl) == FUNCTION_DECL
       && DECL_INITIAL (decl) == 0
       && DECL_EXTERNAL (decl)
@@ -516,9 +516,9 @@  check_global_declaration_1 (tree decl)
       && ! TREE_NO_WARNING (decl)
       && ! TREE_PUBLIC (decl)
       && (warn_unused_function
-	  || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))
+	  || snode->referred_to_p (false)))
     {
-      if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
+      if (snode->referred_to_p (false))
 	pedwarn (input_location, 0, "%q+F used but never defined", decl);
       else
 	warning (OPT_Wunused_function, "%q+F declared %<static%> but never defined", decl);
@@ -533,6 +533,11 @@  check_global_declaration_1 (tree decl)
        || (warn_unused_variable
 	   && TREE_CODE (decl) == VAR_DECL && ! TREE_READONLY (decl)))
       && ! DECL_IN_SYSTEM_HEADER (decl)
+      && ! snode->referred_to_p (false)
+      /* ?? Why are we looking at TREE_USED?  Shouldn't the call to
+	 referred_to_p above be enough?  Apparently not, because the
+	 `__unused__' attribute is not being considered for
+	 referred_to_p.  */
       && ! TREE_USED (decl)
       /* The TREE_USED bit for file-scope decls is kept in the identifier,
 	 to handle multiple external decls in different scopes.  */
@@ -543,6 +548,10 @@  check_global_declaration_1 (tree decl)
       && ! TREE_THIS_VOLATILE (decl)
       /* Global register variables must be declared to reserve them.  */
       && ! (TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl))
+      /* Global ctors and dtors are called by the runtime.  */
+      && (TREE_CODE (decl) != FUNCTION_DECL
+	  || (!DECL_STATIC_CONSTRUCTOR (decl)
+	      && !DECL_STATIC_DESTRUCTOR (decl)))
       /* Otherwise, ask the language.  */
       && lang_hooks.decls.warn_unused_global (decl))
     warning ((TREE_CODE (decl) == FUNCTION_DECL)
@@ -551,18 +560,6 @@  check_global_declaration_1 (tree decl)
 	     "%q+D defined but not used", decl);
 }
 
-/* Issue appropriate warnings for the global declarations in V (of
-   which there are LEN).  */
-
-void
-check_global_declarations (tree *v, int len)
-{
-  int i;
-
-  for (i = 0; i < len; i++)
-    check_global_declaration_1 (v[i]);
-}
-
 /* Emit late debugging information (post compilation) for all global
    declarations in VEC.  */
 
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 56d452f..732f7e9 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -59,8 +59,7 @@  extern void announce_function (tree);
 extern void wrapup_global_declaration_1 (tree);
 extern bool wrapup_global_declaration_2 (tree);
 extern bool wrapup_global_declarations (tree *, int);
-extern void check_global_declaration_1 (tree);
-extern void check_global_declarations (tree *, int);
+extern void check_global_declaration (tree);
 
 extern void emit_debug_global_declarations (tree *, int);