diff --git a/gcc/testsuite/gnat.dg/opt94.adb b/gcc/testsuite/gnat.dg/opt94.adb
new file mode 100644
index 0000000000000000000000000000000000000000..547bef3a918552cd799776a98c592c47f98fc684
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt94.adb
@@ -0,0 +1,17 @@
+-- { dg-do compile }
+-- { dg-options "-O -gnatn -fdump-tree-optimized" }
+
+with Opt94_Pkg; use Opt94_Pkg;
+
+function Opt94 (S : String) return Integer is
+  A : constant String := Get;
+
+begin
+  if Valid_Result (A) then
+    return Result (A);
+  else
+    return -1;
+  end if;
+end;
+
+-- { dg-final { scan-tree-dump-times "worker" 1 "optimized" } }
diff --git a/gcc/testsuite/gnat.dg/opt94_pkg.adb b/gcc/testsuite/gnat.dg/opt94_pkg.adb
new file mode 100644
index 0000000000000000000000000000000000000000..670291712fb8cbee24771bd15c8ccab40f1d333b
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt94_pkg.adb
@@ -0,0 +1,31 @@
+package body Opt94_Pkg is
+
+  function Worker (S : String) return Integer;
+  pragma Pure_Function (Worker);
+
+  function Valid_Result (S : String) return Boolean is
+  begin
+    return Worker (S) > 0;
+  end;
+
+  function Result (S : String) return Integer is
+    R : constant Integer := Worker (S);
+  begin
+    if R > 0 then
+      return R;
+    else
+      raise Program_Error;
+    end if;
+  end;
+
+  function Worker (S : String) return Integer is
+  begin
+    return Character'Pos (S (S'First));
+  end;
+
+  function Get return String is
+  begin
+    return "";
+  end;
+
+end Opt94_Pkg;
diff --git a/gcc/testsuite/gnat.dg/opt94_pkg.ads b/gcc/testsuite/gnat.dg/opt94_pkg.ads
new file mode 100644
index 0000000000000000000000000000000000000000..16e34338d55258857eab2d79b170b37d93c56468
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt94_pkg.ads
@@ -0,0 +1,11 @@
+package Opt94_Pkg is
+
+  function Valid_Result (S : String) return Boolean;
+  pragma Inline (Valid_Result);
+
+  function Result (S : String) return Integer;
+  pragma Inline (Result);
+
+  function Get return String;
+
+end Opt94_Pkg;
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 1dcb31c02676d36fb3a6b074f1a00d20a5e13a94..49a5850f41048154dafbad3b762c4f6b2ad13c15 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -152,30 +152,6 @@ insert_decl_map (copy_body_data *id, tree key, tree value)
     id->decl_map->put (value, value);
 }
 
-/* Insert a tree->tree mapping for ID.  This is only used for
-   variables.  */
-
-static void
-insert_debug_decl_map (copy_body_data *id, tree key, tree value)
-{
-  if (!gimple_in_ssa_p (id->src_cfun))
-    return;
-
-  if (!opt_for_fn (id->dst_fn, flag_var_tracking_assignments))
-    return;
-
-  if (!target_for_debug_bind (key))
-    return;
-
-  gcc_assert (TREE_CODE (key) == PARM_DECL);
-  gcc_assert (VAR_P (value));
-
-  if (!id->debug_map)
-    id->debug_map = new hash_map<tree, tree>;
-
-  id->debug_map->put (key, value);
-}
-
 /* If nonzero, we're remapping the contents of inlined debug
    statements.  If negative, an error has occurred, such as a
    reference to a variable that isn't available in the inlined
@@ -3190,7 +3166,8 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
   else
     gcc_unreachable ();
 
-  if (TREE_CODE (t) == PARM_DECL && id->debug_map
+  if (TREE_CODE (t) == PARM_DECL
+      && id->debug_map
       && (n = id->debug_map->get (t)))
     {
       gcc_assert (VAR_P (*n));
@@ -3460,16 +3437,18 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
      value.  */
   if (TREE_READONLY (p)
       && !TREE_ADDRESSABLE (p)
-      && value && !TREE_SIDE_EFFECTS (value)
+      && value
+      && !TREE_SIDE_EFFECTS (value)
       && !def)
     {
-      /* We may produce non-gimple trees by adding NOPs or introduce
-	 invalid sharing when operand is not really constant.
-	 It is not big deal to prohibit constant propagation here as
-	 we will constant propagate in DOM1 pass anyway.  */
-      if (is_gimple_min_invariant (value)
-	  && useless_type_conversion_p (TREE_TYPE (p),
-						 TREE_TYPE (value))
+      /* We may produce non-gimple trees by adding NOPs or introduce invalid
+	 sharing when the value is not constant or DECL.  And we need to make
+	 sure that it cannot be modified from another path in the callee.  */
+      if ((is_gimple_min_invariant (value)
+	   || (DECL_P (value) && TREE_READONLY (value))
+	   || (auto_var_in_fn_p (value, id->src_fn)
+	       && !TREE_ADDRESSABLE (value)))
+	  && useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value))
 	  /* We have to be very careful about ADDR_EXPR.  Make sure
 	     the base variable isn't a local variable of the inlined
 	     function, e.g., when doing recursive inlining, direct or
@@ -3478,7 +3457,9 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
 	  && ! self_inlining_addr_expr (value, fn))
 	{
 	  insert_decl_map (id, p, value);
-	  insert_debug_decl_map (id, p, var);
+	  if (!id->debug_map)
+	    id->debug_map = new hash_map<tree, tree>;
+	  id->debug_map->put (p, var);
 	  return insert_init_debug_bind (id, bb, var, value, NULL);
 	}
     }
@@ -5128,8 +5109,13 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
     for (tree p = DECL_ARGUMENTS (id->src_fn); p; p = DECL_CHAIN (p))
       if (!TREE_THIS_VOLATILE (p))
 	{
+	  /* The value associated with P is a local temporary only if
+	     there is no value associated with P in the debug map.  */
 	  tree *varp = id->decl_map->get (p);
-	  if (varp && VAR_P (*varp) && !is_gimple_reg (*varp))
+	  if (varp
+	      && VAR_P (*varp)
+	      && !is_gimple_reg (*varp)
+	      && !(id->debug_map && id->debug_map->get (p)))
 	    {
 	      tree clobber = build_clobber (TREE_TYPE (*varp));
 	      gimple *clobber_stmt;
diff --git a/gcc/tree-inline.h b/gcc/tree-inline.h
index f20cff31f0954905395c56da5969f70355bafb8b..ec0e82fe865e41c582cd85ffca82bcc2288e9cde 100644
--- a/gcc/tree-inline.h
+++ b/gcc/tree-inline.h
@@ -150,9 +150,9 @@ struct copy_body_data
   vec<gdebug *> debug_stmts;
 
   /* A map from local declarations in the inlined function to
-     equivalents in the function into which it is being inlined, where
-     the originals have been mapped to a value rather than to a
-     variable.  */
+     equivalents in the function into which it is being inlined,
+     where the originals have been mapped to a value rather than
+     to a variable.  */
   hash_map<tree, tree> *debug_map;
 
   /* A map from the inlined functions dependence info cliques to