Index: cif-code.def
===================================================================
--- cif-code.def	(revision 208829)
+++ cif-code.def	(working copy)
@@ -127,3 +127,7 @@ DEFCIFCODE(USES_COMDAT_LOCAL, CIF_FINAL_
 /* We can't inline because of mismatched caller/callee attributes.  */
 DEFCIFCODE(ATTRIBUTE_MISMATCH, CIF_FINAL_NORMAL,
 	   N_("function attribute mismatch"))
+
+/* We proved that the call is unreachable.  */
+DEFCIFCODE(UNREACHABLE, CIF_FINAL_NORMAL,
+	   N_("unreachable"))
Index: cgraphclones.c
===================================================================
--- cgraphclones.c	(revision 208829)
+++ cgraphclones.c	(working copy)
@@ -238,8 +238,12 @@ cgraph_clone_node (struct cgraph_node *n
   FOR_EACH_VEC_ELT (redirect_callers, i, e)
     {
       /* Redirect calls to the old version node to point to its new
-	 version.  */
-      cgraph_redirect_edge_callee (e, new_node);
+	 version.  The only exception is when the edge was proved to
+	 be unreachable during the clonning procedure.  */
+      if (!e->callee
+	  || DECL_BUILT_IN_CLASS (e->callee->decl) != BUILT_IN_NORMAL
+	  || DECL_FUNCTION_CODE (e->callee->decl) != BUILT_IN_UNREACHABLE)
+        cgraph_redirect_edge_callee (e, new_node);
     }
 
 
Index: ipa-inline.c
===================================================================
--- ipa-inline.c	(revision 208829)
+++ ipa-inline.c	(working copy)
@@ -1685,7 +1685,7 @@ inline_small_functions (void)
       edge = (struct cgraph_edge *) fibheap_extract_min (edge_heap);
       gcc_assert (edge->aux);
       edge->aux = NULL;
-      if (!edge->inline_failed)
+      if (!edge->inline_failed || !edge->callee->analyzed)
 	continue;
 
       /* Be sure that caches are maintained consistent.  
Index: ipa-inline.h
===================================================================
--- ipa-inline.h	(revision 208829)
+++ ipa-inline.h	(working copy)
@@ -285,7 +285,8 @@ static inline int
 estimate_edge_growth (struct cgraph_edge *edge)
 {
 #ifdef ENABLE_CHECKING
-  gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size);
+  gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size
+		       || !edge->callee->analyzed);
 #endif
   return (estimate_edge_size (edge)
 	  - inline_edge_summary (edge)->call_stmt_size);
Index: testsuite/g++.dg/torture/pr60315.C
===================================================================
--- testsuite/g++.dg/torture/pr60315.C	(revision 0)
+++ testsuite/g++.dg/torture/pr60315.C	(revision 0)
@@ -0,0 +1,32 @@
+// { dg-do compile }
+struct Base {
+    virtual int f() = 0;
+};
+
+struct Derived : public Base {
+    virtual int f() final override {
+        return 42;
+    }
+};
+
+extern Base* b;
+
+int main() {
+    return (static_cast<Derived*>(b)->*(&Derived::f))();
+}
+// { dg-do compile }
+struct Base {
+    virtual int f() = 0;
+};
+
+struct Derived : public Base {
+    virtual int f() final override {
+        return 42;
+    }
+};
+
+extern Base* b;
+
+int main() {
+    return (static_cast<Derived*>(b)->*(&Derived::f))();
+}
Index: cgraph.c
===================================================================
--- cgraph.c	(revision 208829)
+++ cgraph.c	(working copy)
@@ -2612,6 +2612,12 @@ verify_edge_corresponds_to_fndecl (struc
       || node->in_other_partition
       || e->callee->in_other_partition)
     return false;
+
+  /* Optimizers can redirect unreachable calls or calls triggering undefined
+     behaviour to builtin_unreachable.  */
+  if (DECL_BUILT_IN_CLASS (e->callee->decl) == BUILT_IN_NORMAL
+      && DECL_FUNCTION_CODE (e->callee->decl) == BUILT_IN_UNREACHABLE)
+    return false;
   node = cgraph_function_or_thunk_node (node, NULL);
 
   if (e->callee->former_clone_of != node->decl
Index: ipa-inline-analysis.c
===================================================================
--- ipa-inline-analysis.c	(revision 208829)
+++ ipa-inline-analysis.c	(working copy)
@@ -746,6 +746,20 @@ static void
 edge_set_predicate (struct cgraph_edge *e, struct predicate *predicate)
 {
   struct inline_edge_summary *es = inline_edge_summary (e);
+
+  /* If the edge is determined to be never executed, redirect it
+     to BUILTIN_UNREACHABLE to save inliner from inlining into it.  */
+  if (predicate && false_predicate_p (predicate) && e->callee)
+    {
+      struct cgraph_node *callee = !e->inline_failed ? e->callee : NULL;
+
+      cgraph_redirect_edge_callee (e,
+				   cgraph_get_create_node
+				     (builtin_decl_implicit (BUILT_IN_UNREACHABLE)));
+      e->inline_failed = CIF_UNREACHABLE;
+      if (callee)
+	cgraph_remove_node_and_inline_clones (callee, NULL);
+    }
   if (predicate && !true_predicate_p (predicate))
     {
       if (!es->predicate)
@@ -1724,12 +1738,20 @@ set_cond_stmt_execution_predicate (struc
 
       FOR_EACH_EDGE (e, ei, bb->succs)
 	{
-	  struct predicate p = add_condition (summary, index, &aggpos,
-					      e->flags & EDGE_TRUE_VALUE
-					      ? code : inverted_code,
-					      gimple_cond_rhs (last));
-	  e->aux = pool_alloc (edge_predicate_pool);
-	  *(struct predicate *) e->aux = p;
+	  enum tree_code this_code = (e->flags & EDGE_TRUE_VALUE
+				      ? code : inverted_code);
+	  /* invert_tree_comparison will return ERROR_MARK on FP
+	     comparsions that are not EQ/NE instead of returning proper
+	     unordered one.  Be sure it is not confused with NON_CONSTANT.  */
+	  if (this_code != ERROR_MARK)
+	    {
+	      struct predicate p = add_condition (summary, index, &aggpos,
+						  e->flags & EDGE_TRUE_VALUE
+						  ? code : inverted_code,
+						  gimple_cond_rhs (last));
+	      e->aux = pool_alloc (edge_predicate_pool);
+	      *(struct predicate *) e->aux = p;
+	    }
 	}
     }
 
Index: ipa-cp.c
===================================================================
--- ipa-cp.c	(revision 208829)
+++ ipa-cp.c	(working copy)
@@ -2811,9 +2811,7 @@ create_specialized_node (struct cgraph_n
       if (aggvals)
 	ipa_dump_agg_replacement_values (dump_file, aggvals);
     }
-  gcc_checking_assert (ipa_node_params_vector.exists ()
-		       && (ipa_node_params_vector.length ()
-			   > (unsigned) cgraph_max_uid));
+  ipa_check_create_node_params ();
   update_profiling_info (node, new_node);
   new_info = IPA_NODE_REF (new_node);
   new_info->ipcp_orig_node = node;
