diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7c07cc430f8becbe0bd7f2be6bfe9558d1d935e9..b97af9a6f31740acc55156767e1d39e9f2f73b79 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,20 @@
+2005-01-20  Ian Lance Taylor  <ian@airs.com>
+
+	PR tree-optimization/13000
+	* tree-inline.c: Include "tree-flow.h".
+	(expand_call_inline): If warn_return_type, warn if non-void inline
+	function falls through.
+	* tree-cfg.c (execute_warn_function_return): Don't warn about
+	control reaching end if TREE_NO_WARNING is set.  Set
+	TREE_NO_WARNING.
+	* gimple-low.c (block_may_fallthru): Don't assume that SWITCH_EXPR
+	has been lowered.
+	* gimplify.c (shortcut_cond_expr): Don't emit a jump over the else
+	branch if we don't need one.
+	* c-typeck.c: Include "tree-flow.h"
+	(c_finish_bc_stmt): Don't add a goto if the current statement
+	list doesn't fall through to the current point.
+
 2005-01-21  Roger Sayle  <roger@eyesopen.com>
 
 	PR rtl-optimization/576
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 186cb62bd2a01c841c88be71e845ec1f2026fda7..a4e4bc9df26efb1c08e7f3b8f7d8902d4dc2d6c9 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -43,6 +43,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "target.h"
 #include "tree-iterator.h"
 #include "tree-gimple.h"
+#include "tree-flow.h"
 
 /* Possible cases of implicit bad conversions.  Used to select
    diagnostic messages in convert_for_assignment.  */
@@ -6762,10 +6763,23 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
 tree
 c_finish_bc_stmt (tree *label_p, bool is_break)
 {
+  bool skip;
   tree label = *label_p;
 
+  /* In switch statements break is sometimes stylistically used after
+     a return statement.  This can lead to spurious warnings about
+     control reaching the end of a non-void function when it is
+     inlined.  Note that we are calling block_may_fallthru with
+     language specific tree nodes; this works because
+     block_may_fallthru returns true when given something it does not
+     understand.  */
+  skip = !block_may_fallthru (cur_stmt_list);
+
   if (!label)
-    *label_p = label = create_artificial_label ();
+    {
+      if (!skip)
+	*label_p = label = create_artificial_label ();
+    }
   else if (TREE_CODE (label) != LABEL_DECL)
     {
       if (is_break)
@@ -6775,6 +6789,9 @@ c_finish_bc_stmt (tree *label_p, bool is_break)
       return NULL_TREE;
     }
 
+  if (skip)
+    return NULL_TREE;
+
   return add_stmt (build1 (GOTO_EXPR, void_type_node, label));
 }
 
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index eb495288eee539726190a584e80d751094c6e5a6..17ba0393c25bda78f8de13e00f740f3e60d995bd 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -278,11 +278,17 @@ block_may_fallthru (tree block)
     case GOTO_EXPR:
     case RETURN_EXPR:
     case RESX_EXPR:
-    case SWITCH_EXPR:
       /* Easy cases.  If the last statement of the block implies 
 	 control transfer, then we can't fall through.  */
       return false;
 
+    case SWITCH_EXPR:
+      /* If SWITCH_LABELS is set, this is lowered, and represents a
+	 branch to a selected label and hence can not fall through.
+	 Otherwise SWITCH_BODY is set, and the switch can fall
+	 through.  */
+      return SWITCH_LABELS (stmt) != NULL_TREE;
+
     case COND_EXPR:
       if (block_may_fallthru (COND_EXPR_THEN (stmt)))
 	return true;
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 12822c4705565772aa4dcffdb2cdc7ebf75989b4..60d35724aaffd9df1a0af3c3aa8f0603bc3ea34e 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1911,7 +1911,7 @@ shortcut_cond_expr (tree expr)
   tree true_label, false_label, end_label, t;
   tree *true_label_p;
   tree *false_label_p;
-  bool emit_end, emit_false;
+  bool emit_end, emit_false, jump_over_else;
   bool then_se = then_ && TREE_SIDE_EFFECTS (then_);
   bool else_se = else_ && TREE_SIDE_EFFECTS (else_);
 
@@ -2013,6 +2013,16 @@ shortcut_cond_expr (tree expr)
   emit_end = (end_label == NULL_TREE);
   emit_false = (false_label == NULL_TREE);
 
+  /* We only emit the jump over the else clause if we have to--if the
+     then clause may fall through.  Otherwise we can wind up with a
+     useless jump and a useless label at the end of gimplified code,
+     which will cause us to think that this conditional as a whole
+     falls through even if it doesn't.  If we then inline a function
+     which ends with such a condition, that can cause us to issue an
+     inappropriate warning about control reaching the end of a
+     non-void function.  */
+  jump_over_else = block_may_fallthru (then_);
+
   pred = shortcut_cond_r (pred, true_label_p, false_label_p);
 
   expr = NULL;
@@ -2021,8 +2031,11 @@ shortcut_cond_expr (tree expr)
   append_to_statement_list (then_, &expr);
   if (else_se)
     {
-      t = build_and_jump (&end_label);
-      append_to_statement_list (t, &expr);
+      if (jump_over_else)
+	{
+	  t = build_and_jump (&end_label);
+	  append_to_statement_list (t, &expr);
+	}
       if (emit_false)
 	{
 	  t = build1 (LABEL_EXPR, void_type_node, false_label);
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 483b2dd81bd8107f7ec9fed19de284b3e297b2e5..93dfc343f8289255f3a42a9326e5ef35e22442e8 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -5677,6 +5677,7 @@ execute_warn_function_return (void)
   /* If we see "return;" in some basic block, then we do reach the end
      without returning a value.  */
   else if (warn_return_type
+	   && !TREE_NO_WARNING (cfun->decl)
 	   && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0
 	   && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (cfun->decl))))
     {
@@ -5697,6 +5698,7 @@ execute_warn_function_return (void)
 		locus = &cfun->function_end_locus;
 	      warning ("%Hcontrol reaches end of non-void function", locus);
 #endif
+	      TREE_NO_WARNING (cfun->decl) = 1;
 	      break;
 	    }
 	}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 247c6873e4d465fced01fc87d263e8ea0458e299..b46276a4e4ce5190f93e12352b78672615bde117 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -41,6 +41,7 @@ Boston, MA 02111-1307, USA.  */
 #include "cgraph.h"
 #include "intl.h"
 #include "tree-mudflap.h"
+#include "tree-flow.h"
 #include "function.h"
 #include "diagnostic.h"
 #include "debug.h"
@@ -1607,9 +1608,22 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
      function itself.  */
   {
     struct cgraph_node *old_node = id->current_node;
+    tree copy;
 
     id->current_node = edge->callee;
-    append_to_statement_list (copy_body (id), &BIND_EXPR_BODY (expr));
+    copy = copy_body (id);
+
+    if (warn_return_type
+	&& !TREE_NO_WARNING (fn)
+	&& !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fn)))
+	&& block_may_fallthru (copy))
+      {
+	warning ("control may reach end of non-void function %qD being inlined",
+		 fn);
+	TREE_NO_WARNING (fn) = 1;
+      }
+
+    append_to_statement_list (copy, &BIND_EXPR_BODY (expr));
     id->current_node = old_node;
   }
   inlined_body = &BIND_EXPR_BODY (expr);