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 88c612020d43d652736346e9fc49752eb01eb5c2..a33743dfb18b12b40a2a99c0b7efb89a4bbc9e7d 100644 (file)
@@ -1,3 +1,23 @@
+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.
index 940d4b18393c7298208f13e55661c1e0353dbd14..9dbaa2846857c9d16cfc951ac437ff9f0bb4099a 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 5531731010e2ae318c8d0fcaf872c710fd4b1c7c..b8adce15454f6aae02dc5b472f3bd7901ead2d67 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 0a29c4b126d4eeeb6e5362e386d7aaa29680c967..7fec383bdd732c20d5198a96318bb64def0442e2 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 b913c6ea8c7de449f9b57f7395b53e6d0ec9860a..52eed8d179cd953162b2dbf059fd31d83f2abebc 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 f58141092110b3ba32a873835ba1758d38255827..85a18bf0b8739937fca265ee2d0962f3a464593a 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 3912d85979029e79cbb39831c205bfe09d99ca92..f3124a7b71ab1f127f865b7397d4dfc475a1bb96 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 848094ce9da6a3b98386f5293d9e414d374b33d1..8574f161526573ebc919f5bd1ea6b4dd2f5ffad7 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 2446de2f800bd4deb5218341e7379771e5bdbc8a..e5d2ae6b3ce0772863b5eaf6b099c37568fe3732 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 6897d5fa2cf71059bdde92cfbdd9486fb9810efd..4e7ec89b96078ed3bb806c84b5c4014597c9c741 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);