This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

-Wmissing-pure/-Wmissing-const/-Wmissing-nothrow


Hi,
this patch adds -Wmissing-const/-Wmissing-pure/-Wmissing-nothrow flags
that makes compiler to warn when it is profitable to decorate function
prototype by corresponding attributes..  Those I used for decorating
libstdc++ so they seem quite useful in practice.  The main catch is to
figure out when the attribute is useful, i.e. when the function can be
called from other compilation unit where body is not known and thus
compiler can't do the job by itself.  This is true for normal externally
visible functions, but not true for i.e. C++ combdat or keyed inlines.

I neded up with the following test
+ static bool
+ function_always_visible_to_compiler_p (tree decl)
+ {
+   if (!TREE_PUBLIC (decl)
+       || DECL_DECLARED_INLINE_P (decl))
+     return true;
+   return false;
+ }
that seems good enough.  Sure user can declare function inline in source file,
not in header and warning would be lost, but so would be lost inlining
oppurtunity.

Bootstrapped/regtested i686-linux, OK?

Honza

	* doc/invoke.texi (-Wmissing-const, -Wmissing-pure, -Wmissing-nothrow):
	Document.
	* toplev.h (warn_function_nothrow): Declare.
	* ipa-pure-const.c: Include toplev.h, flags.h and pointer-set.h.
	(function_always_visible_to_compiler_p, warn_function_nothrow,
	warn_function_pure, warn_function_const): New functions.
	(check_call): Improve debug info.
	(analyze_function): Do not check availability.
	(add_new_function): Check availability.
	(propagate): Output warnings.
	(skip_function_for_local_pure_const): New function.
	(local_pure_const): Use it; output warnings.
	* except.c (set_nothrow_function_flags): Output warnings.
	(common.opt): Add Wmissing-const, Wmissing-nothrow, Wmissing-pure.


	* cp/decl.c (finish_function): Call warn_function_nothrow.

	* g++.dg/opt/nothrow2.C: New testcase.
	* gcc.dg/pure-2.c: New testcase.
	* gcc.dg/const-1.c: New testcase.
Index: doc/invoke.texi
===================================================================
*** doc/invoke.texi	(revision 149176)
--- doc/invoke.texi	(working copy)
*************** Objective-C and Objective-C++ Dialects}.
*** 244,252 ****
  -Wno-int-to-pointer-cast -Wno-invalid-offsetof @gol
  -Winvalid-pch -Wlarger-than=@var{len}  -Wunsafe-loop-optimizations @gol
  -Wlogical-op -Wlong-long @gol
! -Wmain  -Wmissing-braces  -Wmissing-field-initializers @gol
  -Wmissing-format-attribute  -Wmissing-include-dirs @gol
! -Wmissing-noreturn  -Wno-mudflap @gol
  -Wno-multichar  -Wnonnull  -Wno-overflow @gol
  -Woverlength-strings  -Wpacked  -Wpacked-bitfield-compat  -Wpadded @gol
  -Wparentheses  -Wpedantic-ms-format -Wno-pedantic-ms-format @gol
--- 244,252 ----
  -Wno-int-to-pointer-cast -Wno-invalid-offsetof @gol
  -Winvalid-pch -Wlarger-than=@var{len}  -Wunsafe-loop-optimizations @gol
  -Wlogical-op -Wlong-long @gol
! -Wmain  -Wmissing-braces -Wmissing-const -Wmissing-field-initializers @gol
  -Wmissing-format-attribute  -Wmissing-include-dirs @gol
! -Wmissing-noreturn  -Wmissing-nothrow -Wmissing-pure -Wno-mudflap @gol
  -Wno-multichar  -Wnonnull  -Wno-overflow @gol
  -Woverlength-strings  -Wpacked  -Wpacked-bitfield-compat  -Wpadded @gol
  -Wparentheses  -Wpedantic-ms-format -Wno-pedantic-ms-format @gol
*************** adding the @code{noreturn} attribute, ot
*** 3952,3957 ****
--- 3952,3977 ----
  bugs could be introduced.  You will not get a warning for @code{main} in
  hosted C environments.
  
+ @item -Wmissing-const
+ @opindex Wmissing-const
+ @opindex Wno-missing-const
+ @item -Wmissing-pure
+ @opindex Wmissing-pure
+ @opindex Wno-missing-pure
+ Warn about functions which might be candidates for attribute @code{const} and @code{pure}.
+ Warning is not output for functions where compiler can fully decide by itself, only
+ for functions visible in other compilation units and/or those where compiler can not
+ easilly prove fact, that functions is not infinite and thus call to it can be removed
+ when return value is unused.
+ 
+ @item -Wmissing-nothrow
+ @opindex Wmissing-nothrow
+ @opindex Wno-missing-nothrow
+ Warn about functions which might be candidates for attribute @code{nothrow} or,
+ in C++, for decoration via @code{throw ()}.  Warning is not output for
+ functions where compiler can fully decide by itself, only for functions visible
+ in other compilation units.
+ 
  @item -Wmissing-format-attribute
  @opindex Wmissing-format-attribute
  @opindex Wno-missing-format-attribute
Index: toplev.h
===================================================================
*** toplev.h	(revision 149176)
--- toplev.h	(working copy)
*************** extern bool set_src_pwd		       (const c
*** 216,219 ****
--- 216,221 ----
  extern const char *get_random_seed (bool);
  extern const char *set_random_seed (const char *);
  
+ extern void warn_function_nothrow (tree);
+ 
  #endif /* ! GCC_TOPLEV_H */
Index: testsuite/gcc.dg/pure-2.c
===================================================================
*** testsuite/gcc.dg/pure-2.c	(revision 0)
--- testsuite/gcc.dg/pure-2.c	(revision 0)
***************
*** 0 ****
--- 1,57 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -Wmissing-pure" } */
+ 
+ extern int extern_const(int a) __attribute__ ((pure));
+ extern int v;
+ 
+ /* Trivial.  */
+ int
+ foo1(int a)
+ {
+   return v;
+ } /* { dg-warning "candidate for attribute 'const'" "detect const candidate" } */
+ 
+ /* Loops known to be finite and extern const calls should be safe.  */
+ int __attribute__ ((noinline))
+ foo2(int n)
+ {
+   int ret = 0;
+   int i;
+   for (i=0; i<n; i++)
+     ret+=extern_const (i);
+   return ret;
+ } /* { dg-warning "candidate for attribute 'const'" "detect const candidate" } */
+ 
+ /* No warning here; we can work it by ourselves.  */
+ static int __attribute__ ((noinline))
+ foo2b(int n)
+ {
+   int ret = 0;
+   int i;
+   for (i=0; i<n; i++)
+     ret+=extern_const (i);
+   return ret;
+ }
+ 
+ /* Unbounded loops are not safe.  */
+ static int __attribute__ ((noinline))
+ foo3(int n)
+ {
+   int ret = 0;
+   int i;
+   for (i=0; extern_const (i+n); n++)
+     ret+=extern_const (i);
+   return ret;
+ } /* { dg-warning "candidate for attribute 'const' if known to be finite" "detect const candidate" } */
+ 
+ int
+ foo4(int n)
+ {
+   return foo3(n) + foo2b(n);
+ } /* { dg-warning "candidate for attribute 'const' if known to be finite" "detect const candidate" } */
+ 
+ int
+ foo5(int n)
+ {
+   return foo2(n);
+ } /* { dg-warning "candidate for attribute 'const'" "detect const candidate" } */
Index: testsuite/gcc.dg/const-1.c
===================================================================
*** testsuite/gcc.dg/const-1.c	(revision 0)
--- testsuite/gcc.dg/const-1.c	(revision 0)
***************
*** 0 ****
--- 1,56 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -Wmissing-const" } */
+ 
+ extern int extern_const(int a) __attribute__ ((const));
+ 
+ /* Trivial.  */
+ int
+ foo1(int a)
+ {
+   return extern_const (a);
+ } /* { dg-warning "candidate for attribute 'const'" "detect const candidate" } */
+ 
+ /* Loops known to be finite and extern const calls should be safe.  */
+ int __attribute__ ((noinline))
+ foo2(int n)
+ {
+   int ret = 0;
+   int i;
+   for (i=0; i<n; i++)
+     ret+=extern_const (i);
+   return ret;
+ } /* { dg-warning "candidate for attribute 'const'" "detect const candidate" } */
+ 
+ /* No warning here; we can work it by ourselves.  */
+ static int __attribute__ ((noinline))
+ foo2b(int n)
+ {
+   int ret = 0;
+   int i;
+   for (i=0; i<n; i++)
+     ret+=extern_const (i);
+   return ret;
+ }
+ 
+ /* Unbounded loops are not safe.  */
+ static int __attribute__ ((noinline))
+ foo3(int n)
+ {
+   int ret = 0;
+   int i;
+   for (i=0; extern_const (i+n); n++)
+     ret+=extern_const (i);
+   return ret;
+ } /* { dg-warning "candidate for attribute 'const' if known to be finite" "detect const candidate" } */
+ 
+ int
+ foo4(int n)
+ {
+   return foo3(n) + foo2b(n);
+ } /* { dg-warning "candidate for attribute 'const' if known to be finite" "detect const candidate" } */
+ 
+ int
+ foo5(int n)
+ {
+   return foo2(n);
+ } /* { dg-warning "candidate for attribute 'const'" "detect const candidate" } */
Index: testsuite/g++.dg/opt/nothrow2.C
===================================================================
*** testsuite/g++.dg/opt/nothrow2.C	(revision 0)
--- testsuite/g++.dg/opt/nothrow2.C	(revision 0)
***************
*** 0 ****
--- 1,6 ----
+ // { dg-options "-O2 -Wmissing-nothrow" }
+ 
+ int t ()
+ {
+   return 1;
+ } // { dg-warning "candidate for attribute `nothrow`" }
Index: cp/decl.c
===================================================================
*** cp/decl.c	(revision 149176)
--- cp/decl.c	(working copy)
*************** finish_function (int flags)
*** 12298,12304 ****
        && !cp_function_chain->can_throw
        && !flag_non_call_exceptions
        && !DECL_REPLACEABLE_P (fndecl))
!     TREE_NOTHROW (fndecl) = 1;
  
    /* This must come after expand_function_end because cleanups might
       have declarations (from inline functions) that need to go into
--- 12298,12307 ----
        && !cp_function_chain->can_throw
        && !flag_non_call_exceptions
        && !DECL_REPLACEABLE_P (fndecl))
!     {
!       TREE_NOTHROW (fndecl) = 1;
!       warn_function_nothrow (fndecl);
!     }
  
    /* This must come after expand_function_end because cleanups might
       have declarations (from inline functions) that need to go into
Index: ipa-pure-const.c
===================================================================
*** ipa-pure-const.c	(revision 149176)
--- ipa-pure-const.c	(working copy)
*************** along with GCC; see the file COPYING3.  
*** 51,56 ****
--- 51,59 ----
  #include "diagnostic.h"
  #include "langhooks.h"
  #include "target.h"
+ #include "toplev.h"
+ #include "flags.h"
+ #include "pointer-set.h"
  #include "cfgloop.h"
  #include "tree-scalar-evolution.h"
  
*************** static struct cgraph_node_hook_list *fun
*** 104,109 ****
--- 108,197 ----
  static struct cgraph_2node_hook_list *node_duplication_hook_holder;
  static struct cgraph_node_hook_list *node_removal_hook_holder;
  
+ /* Try to guess if function body will always be visible to compiler
+    when compiling the call and whether compiler will be able
+    to propagate the information by itself.  */
+ 
+ static bool
+ function_always_visible_to_compiler_p (tree decl)
+ {
+   if (!TREE_PUBLIC (decl)
+       || DECL_DECLARED_INLINE_P (decl))
+     return true;
+   return false;
+ }
+ 
+ void
+ warn_function_nothrow (tree decl)
+ {
+   static struct pointer_set_t *warned_about;
+ 
+   if (!warn_missing_nothrow || TREE_THIS_VOLATILE (decl))
+     return;
+   if (function_always_visible_to_compiler_p (decl))
+     return;
+   
+   if (!warned_about)
+     warned_about = pointer_set_create ();
+   if (pointer_set_contains (warned_about, decl))
+     return;
+   pointer_set_insert (warned_about, decl);
+   warning (OPT_Wmissing_nothrow, "%Jfunction might be possible candidate "
+            "for attribute %<nothrow%> or %<throw ()%> marker in C++ code.",
+ 	   decl);
+ }
+ 
+ static void
+ warn_function_pure (tree decl, bool known_finite)
+ {
+   static struct pointer_set_t *warned_about;
+ 
+   if (!warn_missing_pure || TREE_THIS_VOLATILE (decl))
+     return;
+   if (!warned_about)
+     warned_about = pointer_set_create ();
+   if (pointer_set_contains (warned_about, decl))
+     return;
+   pointer_set_insert (warned_about, decl);
+   if (!known_finite)
+     {
+       warning (OPT_Wmissing_pure, "%Jfunction might be possible candidate "
+                "for attribute %<pure%> if it is known to be finite.",
+ 	       decl);
+       return;
+     }
+   if (function_always_visible_to_compiler_p (decl))
+     return;
+   warning (OPT_Wmissing_pure, "%Jfunction might be possible candidate "
+            "for attribute %<pure%>.",
+ 	   decl);
+ }
+ 
+ static void
+ warn_function_const (tree decl, bool known_finite)
+ {
+   static struct pointer_set_t *warned_about;
+ 
+   if (!warn_missing_const || TREE_THIS_VOLATILE (decl))
+     return;
+   if (!warned_about)
+     warned_about = pointer_set_create ();
+   if (pointer_set_contains (warned_about, decl))
+     return;
+   pointer_set_insert (warned_about, decl);
+   if (!known_finite)
+     {
+       warning (OPT_Wmissing_const, "%Jfunction might be possible candidate "
+                "for attribute %<const%> if it is known to be finite.",
+ 	       decl);
+       return;
+     }
+   if (function_always_visible_to_compiler_p (decl))
+     return;
+   warning (OPT_Wmissing_const, "%Jfunction might be possible candidate "
+            "for attribute %<const%>.",
+ 	   decl);
+ }
  /* Init the function state.  */
  
  static void
*************** check_call (funct_state local, gimple ca
*** 328,334 ****
  
    /* When not in IPA mode, we can still handle self recursion.  */
    if (!ipa && callee_t == current_function_decl)
!     local->looping = true;
    /* The callee is either unknown (indirect call) or there is just no
       scannable code for it (external call) .  We look to see if there
       are any bits available for the callee (such as by declaration or
--- 416,426 ----
  
    /* When not in IPA mode, we can still handle self recursion.  */
    if (!ipa && callee_t == current_function_decl)
!     {
!       if (dump_file)
!         fprintf (dump_file, "    Recursive call can loop.\n");
!       local->looping = true;
!     }
    /* The callee is either unknown (indirect call) or there is just no
       scannable code for it (external call) .  We look to see if there
       are any bits available for the callee (such as by declaration or
*************** check_call (funct_state local, gimple ca
*** 357,368 ****
        if (flags & ECF_CONST) 
  	{
            if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t))
!             local->looping = true;
  	 }
        else if (flags & ECF_PURE) 
  	{
            if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t))
!             local->looping = true;
  	  if (dump_file)
  	    fprintf (dump_file, "    pure function call in not const\n");
  	  if (local->pure_const_state == IPA_CONST)
--- 449,468 ----
        if (flags & ECF_CONST) 
  	{
            if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t))
! 	    {
! 	      if (dump_file)
! 		fprintf (dump_file, "    calls looping pure.\n");
!               local->looping = true;
! 	    }
  	 }
        else if (flags & ECF_PURE) 
  	{
            if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t))
! 	    {
! 	      if (dump_file)
! 		fprintf (dump_file, "    calls looping const.\n");
!               local->looping = true;
! 	    }
  	  if (dump_file)
  	    fprintf (dump_file, "    pure function call in not const\n");
  	  if (local->pure_const_state == IPA_CONST)
*************** analyze_function (struct cgraph_node *fn
*** 488,504 ****
    funct_state l;
    basic_block this_block;
  
-   if (cgraph_function_body_availability (fn) <= AVAIL_OVERWRITABLE)
-     {
-       if (dump_file)
-         fprintf (dump_file, "Function is not available or overwrittable; not analyzing.\n");
-       return NULL;
-     }
- 
    l = XCNEW (struct funct_state_d);
    l->pure_const_state = IPA_CONST;
    l->state_previously_known = IPA_NEITHER;
    l->looping_previously_known = true;
    l->looping = false;
    l->can_throw = false;
  
--- 588,597 ----
    funct_state l;
    basic_block this_block;
  
    l = XCNEW (struct funct_state_d);
    l->pure_const_state = IPA_CONST;
    l->state_previously_known = IPA_NEITHER;
    l->looping_previously_known = true;
    l->looping = false;
    l->can_throw = false;
  
*************** add_new_function (struct cgraph_node *no
*** 608,614 ****
       since all we would be interested in are the addressof
       operations.  */
    visited_nodes = pointer_set_create ();
!   set_function_state (node, analyze_function (node, true));
    pointer_set_destroy (visited_nodes);
    visited_nodes = NULL;
  }
--- 702,709 ----
       since all we would be interested in are the addressof
       operations.  */
    visited_nodes = pointer_set_create ();
!   if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE)
!     set_function_state (node, analyze_function (node, true));
    pointer_set_destroy (visited_nodes);
    visited_nodes = NULL;
  }
*************** propagate (void)
*** 779,797 ****
  	  switch (this_state)
  	    {
  	    case IPA_CONST:
! 	      if (!TREE_READONLY (w->decl) && dump_file)
! 		fprintf (dump_file, "Function found to be %sconst: %s\n",  
! 			 this_looping ? "looping " : "",
! 			 cgraph_node_name (w)); 
  	      TREE_READONLY (w->decl) = 1;
  	      DECL_LOOPING_CONST_OR_PURE_P (w->decl) = this_looping;
  	      break;
  	      
  	    case IPA_PURE:
! 	      if (!DECL_PURE_P (w->decl) && dump_file)
! 		fprintf (dump_file, "Function found to be %spure: %s\n",  
! 			 this_looping ? "looping " : "",
! 			 cgraph_node_name (w)); 
  	      DECL_PURE_P (w->decl) = 1;
  	      DECL_LOOPING_CONST_OR_PURE_P (w->decl) = this_looping;
  	      break;
--- 874,900 ----
  	  switch (this_state)
  	    {
  	    case IPA_CONST:
! 	      if (!TREE_READONLY (w->decl))
! 		{
! 	          warn_function_const (w->decl, !this_looping);
! 		  if (dump_file)
! 		    fprintf (dump_file, "Function found to be %sconst: %s\n",  
! 			     this_looping ? "looping " : "",
! 			     cgraph_node_name (w)); 
! 		}
  	      TREE_READONLY (w->decl) = 1;
  	      DECL_LOOPING_CONST_OR_PURE_P (w->decl) = this_looping;
  	      break;
  	      
  	    case IPA_PURE:
! 	      if (!DECL_PURE_P (w->decl))
! 		{
! 	          warn_function_pure (w->decl, !this_looping);
! 		  if (dump_file)
! 		    fprintf (dump_file, "Function found to be %spure: %s\n",  
! 			     this_looping ? "looping " : "",
! 			     cgraph_node_name (w)); 
! 		}
  	      DECL_PURE_P (w->decl) = 1;
  	      DECL_LOOPING_CONST_OR_PURE_P (w->decl) = this_looping;
  	      break;
*************** propagate (void)
*** 872,877 ****
--- 975,981 ----
  	    {
  	      struct cgraph_edge *e;
  	      TREE_NOTHROW (w->decl) = true;
+ 	      warn_function_nothrow (w->decl);
  	      for (e = w->callers; e; e = e->next_caller)
  	        e->can_throw_external = false;
  	      if (dump_file)
*************** struct ipa_opt_pass_d pass_ipa_pure_cons
*** 939,954 ****
   NULL					/* variable_transform */
  };
  
! /* Simple local pass for pure const discovery reusing the analysis from
!    ipa_pure_const.   This pass is effective when executed together with
!    other optimization passes in early optimization pass queue.  */
  
! static unsigned int
! local_pure_const (void)
  {
-   bool changed = false;
-   funct_state l;
- 
    /* Because we do not schedule pass_fixup_cfg over whole program after early optimizations
       we must not promote functions that are called by already processed functions.  */
  
--- 1043,1053 ----
   NULL					/* variable_transform */
  };
  
! /* Return true if function should be skipped for local pure const analysis.  */
  
! static bool
! skip_function_for_local_pure_const (void)
  {
    /* Because we do not schedule pass_fixup_cfg over whole program after early optimizations
       we must not promote functions that are called by already processed functions.  */
  
*************** local_pure_const (void)
*** 956,980 ****
      {
        if (dump_file)
          fprintf (dump_file, "Function called in recursive cycle; ignoring\n");
!       return 0;
      }
! 
!   l = analyze_function (cgraph_node (current_function_decl), false);
!   if (!l)
      {
        if (dump_file)
!         fprintf (dump_file, "Function has wrong visibility; ignoring\n");
!       return 0;
      }
  
    switch (l->pure_const_state)
      {
      case IPA_CONST:
        if (!TREE_READONLY (current_function_decl))
  	{
! 	  TREE_READONLY (current_function_decl) = 1;
! 	  DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
! 	  changed = true;
  	  if (dump_file)
  	    fprintf (dump_file, "Function found to be %sconst: %s\n",
  		     l->looping ? "looping " : "",
--- 1055,1101 ----
      {
        if (dump_file)
          fprintf (dump_file, "Function called in recursive cycle; ignoring\n");
!       return true;
      }
!   if (cgraph_function_body_availability (cgraph_node (current_function_decl))
!       <= AVAIL_OVERWRITABLE)
      {
        if (dump_file)
!         fprintf (dump_file, "Function is not available or overwrittable; not analyzing.\n");
!       return true;
      }
+   return false;
+ }
+ 
+ /* Simple local pass for pure const discovery reusing the analysis from
+    ipa_pure_const.   This pass is effective when executed together with
+    other optimization passes in early optimization pass queue.  */
+ 
+ static unsigned int
+ local_pure_const (void)
+ {
+   bool changed = false;
+   funct_state l;
+   bool skip;
+ 
+   skip = skip_function_for_local_pure_const ();
+   if (!warn_missing_const && !warn_missing_nothrow && !warn_missing_pure
+       && skip)
+     return 0;
+   l = analyze_function (cgraph_node (current_function_decl), false);
  
    switch (l->pure_const_state)
      {
      case IPA_CONST:
        if (!TREE_READONLY (current_function_decl))
  	{
! 	  warn_function_const (current_function_decl, !l->looping);
! 	  if (!skip)
! 	    {
! 	      TREE_READONLY (current_function_decl) = 1;
! 	      DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
! 	      changed = true;
! 	    }
  	  if (dump_file)
  	    fprintf (dump_file, "Function found to be %sconst: %s\n",
  		     l->looping ? "looping " : "",
*************** local_pure_const (void)
*** 984,991 ****
        else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
  	       && !l->looping)
  	{
! 	  DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = false;
! 	  changed = true;
  	  if (dump_file)
  	    fprintf (dump_file, "Function found to be non-looping: %s\n",
  		     lang_hooks.decl_printable_name (current_function_decl,
--- 1105,1115 ----
        else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
  	       && !l->looping)
  	{
! 	  if (!skip)
! 	    {
! 	      DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = false;
! 	      changed = true;
! 	    }
  	  if (dump_file)
  	    fprintf (dump_file, "Function found to be non-looping: %s\n",
  		     lang_hooks.decl_printable_name (current_function_decl,
*************** local_pure_const (void)
*** 994,1004 ****
        break;
  
      case IPA_PURE:
!       if (!TREE_READONLY (current_function_decl))
  	{
! 	  DECL_PURE_P (current_function_decl) = 1;
! 	  DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
! 	  changed = true;
  	  if (dump_file)
  	    fprintf (dump_file, "Function found to be %spure: %s\n",
  		     l->looping ? "looping " : "",
--- 1118,1132 ----
        break;
  
      case IPA_PURE:
!       if (!DECL_PURE_P (current_function_decl))
  	{
! 	  if (!skip)
! 	    {
! 	      DECL_PURE_P (current_function_decl) = 1;
! 	      DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
! 	      changed = true;
! 	    }
! 	  warn_function_pure (current_function_decl, !l->looping);
  	  if (dump_file)
  	    fprintf (dump_file, "Function found to be %spure: %s\n",
  		     l->looping ? "looping " : "",
*************** local_pure_const (void)
*** 1008,1015 ****
        else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
  	       && !l->looping)
  	{
! 	  DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = false;
! 	  changed = true;
  	  if (dump_file)
  	    fprintf (dump_file, "Function found to be non-looping: %s\n",
  		     lang_hooks.decl_printable_name (current_function_decl,
--- 1136,1146 ----
        else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
  	       && !l->looping)
  	{
! 	  if (!skip)
! 	    {
! 	      DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = false;
! 	      changed = true;
! 	    }
  	  if (dump_file)
  	    fprintf (dump_file, "Function found to be non-looping: %s\n",
  		     lang_hooks.decl_printable_name (current_function_decl,
*************** local_pure_const (void)
*** 1022,1034 ****
      }
    if (!l->can_throw && !TREE_NOTHROW (current_function_decl))
      {
!       struct cgraph_edge *e;
! 
!       TREE_NOTHROW (current_function_decl) = true;
!       for (e = cgraph_node (current_function_decl)->callers;
!            e; e = e->next_caller)
! 	e->can_throw_external = false;
!       changed = true;
        if (dump_file)
  	fprintf (dump_file, "Function found to be nothrow: %s\n",
  		 lang_hooks.decl_printable_name (current_function_decl,
--- 1153,1168 ----
      }
    if (!l->can_throw && !TREE_NOTHROW (current_function_decl))
      {
!       warn_function_nothrow (current_function_decl);
!       if (!skip)
! 	{
! 	  struct cgraph_edge *e;
! 	  TREE_NOTHROW (current_function_decl) = true;
! 	  for (e = cgraph_node (current_function_decl)->callers;
! 	       e; e = e->next_caller)
! 	    e->can_throw_external = false;
! 	  changed = true;
! 	}
        if (dump_file)
  	fprintf (dump_file, "Function found to be nothrow: %s\n",
  		 lang_hooks.decl_printable_name (current_function_decl,
Index: except.c
===================================================================
*** except.c	(revision 149176)
--- except.c	(working copy)
*************** set_nothrow_function_flags (void)
*** 3369,3374 ****
--- 3369,3376 ----
  	    return 0;
  	  }
        }
+   if (crtl->nothrow)
+     warn_function_nothrow (current_function_decl);
    if (crtl->nothrow
        && (cgraph_function_body_availability (cgraph_node
  					     (current_function_decl))
Index: common.opt
===================================================================
*** common.opt	(revision 149176)
--- common.opt	(working copy)
*************** Wunsafe-loop-optimizations
*** 132,141 ****
--- 132,153 ----
  Common Var(warn_unsafe_loop_optimizations) Warning
  Warn if the loop cannot be optimized due to nontrivial assumptions.
  
+ Wmissing-const
+ Common Var(warn_missing_const) Warning
+ Warn about functions which might be candidates for __attribute__((const))
+ 
+ Wmissing-nothrow
+ Common Var(warn_missing_nothrow) Warning
+ Warn about functions which might be candidates for __attribute__((nothrow))
+ 
  Wmissing-noreturn
  Common Var(warn_missing_noreturn) Warning
  Warn about functions which might be candidates for __attribute__((noreturn))
  
+ Wmissing-pure
+ Common Var(warn_missing_pure) Warning
+ Warn about functions which might be candidates for __attribute__((pure))
+ 
  Wmudflap
  Common Var(warn_mudflap) Init(1) Warning
  Warn about constructs not instrumented by -fmudflap


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]