c-decl.c (warn_missing_noreturn): Remove.
authorRichard Henderson <rth@cygnus.com>
Fri, 6 Oct 2000 06:01:27 +0000 (23:01 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Fri, 6 Oct 2000 06:01:27 +0000 (23:01 -0700)
        * c-decl.c (warn_missing_noreturn): Remove.
        (c_expand_body): Don't set or check can_reach_end.
        * c-tree.h (warn_missing_noreturn): Move ...
        * flags.h: ... here.
        (can_reach_end): Remove.
        * flow.c (check_function_return_warnings): New.
        (make_edges): No edge to exit for noreturn sibcalls.
        * function.c (expand_function_end): Save the return value
        clobber instruction.
        (mark_function_status): Mark it.
        * function.h (struct function): Add x_clobber_return_insn.
        * jump.c (can_reach_end): Remove.
        (calculate_can_reach_end): Remove.
        (jump_optimize_1): Don't call it.
        * output.h (check_function_return_warnings): Declare.
        * toplev.c (warn_missing_noreturn): Move from c-decl.c
        (rest_of_compilation): Call check_function_return_warnings.

From-SVN: r36750

gcc/ChangeLog
gcc/c-decl.c
gcc/c-tree.h
gcc/flags.h
gcc/flow.c
gcc/function.c
gcc/function.h
gcc/jump.c
gcc/output.h
gcc/toplev.c

index 88c6120..a33743d 100644 (file)
@@ -1,5 +1,25 @@
 2000-10-05  Richard Henderson  <rth@cygnus.com>
 
+       * c-decl.c (warn_missing_noreturn): Remove.
+       (c_expand_body): Don't set or check can_reach_end.
+       * c-tree.h (warn_missing_noreturn): Move ...
+       * flags.h: ... here.
+       (can_reach_end): Remove.
+       * flow.c (check_function_return_warnings): New.
+       (make_edges): No edge to exit for noreturn sibcalls.
+       * function.c (expand_function_end): Save the return value
+       clobber instruction.
+       (mark_function_status): Mark it.
+       * function.h (struct function): Add x_clobber_return_insn.
+       * jump.c (can_reach_end): Remove.
+       (calculate_can_reach_end): Remove.
+       (jump_optimize_1): Don't call it.
+       * output.h (check_function_return_warnings): Declare.
+       * toplev.c (warn_missing_noreturn): Move from c-decl.c
+       (rest_of_compilation): Call check_function_return_warnings.
+
+2000-10-05  Richard Henderson  <rth@cygnus.com>
+
        * Makefile.in (NM_FOR_TARGET): New.
        (libgcc.mk): Pass SHLIB_MKMAP, SHLIB_MAPFILES.
        (libgcc.a, stmp-multilib): Pass NM_FOR_TARGET.
index 940d4b1..9dbaa28 100644 (file)
@@ -403,10 +403,6 @@ int warn_cast_qual;
 
 int warn_bad_function_cast;
 
-/* Warn about functions which might be candidates for attribute noreturn.  */
-
-int warn_missing_noreturn;
-
 /* Warn about traditional constructs whose meanings changed in ANSI C.  */
 
 int warn_traditional;
@@ -6760,9 +6756,6 @@ c_expand_body (fndecl, nested_p)
   /* Generate rtl for function exit.  */
   expand_function_end (input_filename, lineno, 0);
 
-  /* So we can tell if jump_optimize sets it to 1.  */
-  can_reach_end = 0;
-
   /* If this is a nested function, protect the local variables in the stack
      above us from being collected while we're compiling this function.  */
   if (nested_p)
@@ -6775,25 +6768,11 @@ c_expand_body (fndecl, nested_p)
   if (nested_p)
     ggc_pop_context ();
 
-  current_function_returns_null |= can_reach_end;
-
-  if (warn_missing_noreturn
-      && !TREE_THIS_VOLATILE (fndecl)
-      && !current_function_returns_null
-      && !current_function_returns_value)
-    warning ("function might be possible candidate for attribute `noreturn'");
-
-  if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null)
-    warning ("`noreturn' function does return");
-  else if (warn_return_type && can_reach_end
-          && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl))))
-    /* If this function returns non-void and control can drop through,
-       complain.  */
-    warning ("control reaches end of non-void function");
   /* With just -W, complain only if function returns both with
      and without a value.  */
-  else if (extra_warnings
-          && current_function_returns_value && current_function_returns_null)
+  if (extra_warnings
+      && current_function_returns_value
+      && current_function_returns_null)
     warning ("this function may return with or without a value");
 
   /* If requested, warn about function definitions where the function will
index 5531731..b8adce1 100644 (file)
@@ -342,10 +342,6 @@ extern int warn_cast_qual;
 
 extern int warn_bad_function_cast;
 
-/* Warn about functions which might be candidates for attribute noreturn. */
-
-extern int warn_missing_noreturn;
-
 /* Warn about traditional constructs whose meanings changed in ANSI C.  */
 
 extern int warn_traditional;
index 0a29c4b..7fec383 100644 (file)
@@ -132,6 +132,10 @@ extern int warn_switch;
 
 extern int warn_return_type;
 
+/* Warn about functions which might be candidates for attribute noreturn. */
+
+extern int warn_missing_noreturn;
+
 /* Nonzero means warn about pointer casts that increase the required
    alignment of the target type (and might therefore lead to a crash
    due to a misaligned access).  */
@@ -547,11 +551,6 @@ extern int flag_renumber_insns;
 
 extern int frame_pointer_needed;
 
-/* Set nonzero if jump_optimize finds that control falls through
-   at the end of the function.  */
-
-extern int can_reach_end;
-
 /* Nonzero if GCC must add code to check memory access (used by Checker).  */
 
 extern int flag_check_memory_usage;
index b913c6e..52eed8d 100644 (file)
@@ -511,6 +511,43 @@ find_basic_blocks (f, nregs, file)
 #endif
 }
 
+void
+check_function_return_warnings ()
+{
+  if (warn_missing_noreturn
+      && !TREE_THIS_VOLATILE (cfun->decl)
+      && EXIT_BLOCK_PTR->pred == NULL)
+    warning ("function might be possible candidate for attribute `noreturn'");
+
+  /* If we have a path to EXIT, then we do return.  */
+  if (TREE_THIS_VOLATILE (cfun->decl)
+      && EXIT_BLOCK_PTR->pred != NULL)
+    warning ("`noreturn' function does return");
+
+  /* If the clobber_return_insn appears in some basic block, then we
+     do reach the end without returning a value.  */
+  else if (warn_return_type
+          && cfun->x_clobber_return_insn != NULL
+          && EXIT_BLOCK_PTR->pred != NULL)
+    {
+      int max_uid = get_max_uid ();
+
+      /* If clobber_return_insn was excised by jump1, then renumber_insns
+        can make max_uid smaller than the number still recorded in our rtx.
+        That's fine, since this is a quick way of verifying that the insn
+        is no longer in the chain.  */
+      if (INSN_UID (cfun->x_clobber_return_insn) < max_uid)
+       {
+         /* Recompute insn->block mapping, since the initial mapping is
+            set before we delete unreachable blocks.  */
+         compute_bb_for_insn (max_uid);
+
+         if (BLOCK_FOR_INSN (cfun->x_clobber_return_insn) != NULL)
+           warning ("control reaches end of non-void function");
+       }
+    }
+}
+
 /* Count the basic blocks of the function.  */
 
 static int
@@ -1115,8 +1152,11 @@ make_edges (label_value_list)
         wouldn't have created the sibling call in the first place.  */
 
       if (code == CALL_INSN && SIBLING_CALL_P (insn))
-       make_edge (edge_cache, bb, EXIT_BLOCK_PTR,
-                  EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
+       {
+         if (! find_reg_note (insn, REG_NORETURN, NULL_RTX))
+           make_edge (edge_cache, bb, EXIT_BLOCK_PTR,
+                      EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
+       }
       else
 
       /* If this is a CALL_INSN, then mark it as reaching the active EH
index f581410..85a18bf 100644 (file)
@@ -6658,12 +6658,20 @@ expand_function_end (filename, line, end_bindings)
 
   if (return_label)
     {
+      rtx before, after;
+
       /* Before the return label, clobber the return registers so that
          they are not propogated live to the rest of the function.  This
         can only happen with functions that drop through; if there had
         been a return statement, there would have either been a return
         rtx, or a jump to the return label.  */
+
+      before = get_last_insn ();
       clobber_return_register ();
+      after = get_last_insn ();
+
+      if (before != after)
+       cfun->x_clobber_return_insn = after;
 
       emit_label (return_label);
     }
@@ -7429,6 +7437,7 @@ mark_function_status (p)
   ggc_mark_tree (p->x_context_display);
   ggc_mark_tree (p->x_trampoline_list);
   ggc_mark_rtx (p->epilogue_delay_list);
+  ggc_mark_rtx (p->x_clobber_return_insn);
 
   mark_temp_slot (p->x_temp_slots);
 
index 3912d85..f3124a7 100644 (file)
@@ -373,6 +373,11 @@ struct function
      needed by inner routines.  */
   rtx x_arg_pointer_save_area;
 
+  /* If the function returns non-void, we will emit a clobber of the
+     return registers just in case the user fell off the end without
+     returning a proper value.  This is that insn.  */
+  rtx x_clobber_return_insn;
+
   /* Offset to end of allocated area of stack frame.
      If stack grows down, this is the address of the last stack slot allocated.
      If stack grows up, this is the address for the next slot.  */
index 848094c..8574f16 100644 (file)
@@ -95,10 +95,6 @@ static rtx *jump_chain;
 
 static int max_jump_chain;
 
-/* Set nonzero by jump_optimize if control can fall through
-   to the end of the function.  */
-int can_reach_end;
-
 /* Indicates whether death notes are significant in cross jump analysis.
    Normally they are not significant, because of A and B jump to C,
    and R dies in A, it must die in B.  But this might not be true after
@@ -112,7 +108,6 @@ static void delete_barrier_successors       PARAMS ((rtx));
 static void mark_all_labels            PARAMS ((rtx, int));
 static rtx delete_unreferenced_labels  PARAMS ((rtx));
 static void delete_noop_moves          PARAMS ((rtx));
-static int calculate_can_reach_end     PARAMS ((rtx, int));
 static int duplicate_loop_exit_test    PARAMS ((rtx));
 static void find_cross_jump            PARAMS ((rtx, rtx, int, rtx *, rtx *));
 static void do_cross_jump              PARAMS ((rtx, rtx, rtx));
@@ -743,13 +738,6 @@ jump_optimize_1 (f, cross_jump, noop_moves, after_regscan,
        }
   }
 
-  /* CAN_REACH_END is persistent for each function.  Once set it should
-     not be cleared.  This is especially true for the case where we
-     delete the NOTE_FUNCTION_END note.  CAN_REACH_END is cleared by
-     the front-end before compiling each function.  */
-  if (! minimal && calculate_can_reach_end (last_insn, optimize != 0))
-    can_reach_end = 1;
-
 end:
   /* Clean up.  */
   free (jump_chain);
@@ -1062,66 +1050,6 @@ delete_noop_moves (f)
     }
 }
 
-/* See if there is still a NOTE_INSN_FUNCTION_END in this function.
-   If so indicate that this function can drop off the end by returning
-   1, else return 0.
-
-   CHECK_DELETED indicates whether we must check if the note being
-   searched for has the deleted flag set.
-
-   DELETE_FINAL_NOTE indicates whether we should delete the note
-   if we find it.  */
-
-static int
-calculate_can_reach_end (last, delete_final_note)
-     rtx last;
-     int delete_final_note;
-{
-  rtx insn = last;
-  int n_labels = 1;
-
-  while (insn != NULL_RTX)
-    {
-      int ok = 0;
-
-      /* One label can follow the end-note: the return label.  */
-      if (GET_CODE (insn) == CODE_LABEL && n_labels-- > 0)
-       ok = 1;
-      /* Ordinary insns can follow it if returning a structure.  */
-      else if (GET_CODE (insn) == INSN)
-       ok = 1;
-      /* If machine uses explicit RETURN insns, no epilogue,
-        then one of them follows the note.  */
-      else if (GET_CODE (insn) == JUMP_INSN
-              && GET_CODE (PATTERN (insn)) == RETURN)
-       ok = 1;
-      /* A barrier can follow the return insn.  */
-      else if (GET_CODE (insn) == BARRIER)
-       ok = 1;
-      /* Other kinds of notes can follow also.  */
-      else if (GET_CODE (insn) == NOTE
-              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
-       ok = 1;
-
-      if (ok != 1)
-       break;
-
-      insn = PREV_INSN (insn);
-    }
-
-  /* See if we backed up to the appropriate type of note.  */
-  if (insn != NULL_RTX
-      && GET_CODE (insn) == NOTE
-      && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END)
-    {
-      if (delete_final_note)
-       delete_insn (insn);
-      return 1;
-    }
-
-  return 0;
-}
-
 /* LOOP_START is a NOTE_INSN_LOOP_BEG note that is followed by an unconditional
    jump.  Assume that this unconditional jump is to the exit test code.  If
    the code is sufficiently simple, make a copy of it before INSN,
index 2446de2..e5d2ae6 100644 (file)
@@ -136,6 +136,7 @@ extern void find_basic_blocks               PARAMS ((rtx, int, FILE *));
 extern void cleanup_cfg                        PARAMS ((rtx));
 extern void free_basic_block_vars     PARAMS ((int));
 extern void set_block_num             PARAMS ((rtx, int));
+extern void check_function_return_warnings PARAMS ((void));
 #endif
 
 /* Functions in varasm.c.  */
index 6897d5f..4e7ec89 100644 (file)
@@ -1405,6 +1405,10 @@ int warn_padded;
 
 int warn_disabled_optimization;
 
+/* Warn about functions which might be candidates for attribute noreturn.  */
+
+int warn_missing_noreturn;
+
 /* Likewise for -W.  */
 
 lang_independent_options W_options[] =
@@ -3209,6 +3213,7 @@ rest_of_compilation (decl)
 
   find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
   cleanup_cfg (insns);
+  check_function_return_warnings ();
 
   close_dump_file (DFI_cfg, print_rtl_with_bb, insns);