diff --git a/gcc/gimple.c b/gcc/gimple.c
index e3e508daf2f..e8246b72cc9 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -1543,7 +1543,7 @@ gimple_call_arg_flags (const gcall *stmt, unsigned arg)
 	  if (fnspec.arg_direct_p (arg))
 	    flags |= EAF_DIRECT;
 	  if (fnspec.arg_noescape_p (arg))
-	    flags |= EAF_NOESCAPE;
+	    flags |= EAF_NOESCAPE | EAF_NODIRECTESCAPE;
 	  if (fnspec.arg_readonly_p (arg))
 	    flags |= EAF_NOCLOBBER;
 	}
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 313a6af2253..e457b917b98 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -110,6 +110,10 @@ struct die_struct;
 /* Nonzero if the argument is not used by the function.  */
 #define EAF_UNUSED		(1 << 3)
 
+/* Nonzero if the argument itself does not escape but memory
+   referenced by it can escape.  */
+#define EAF_NODIRECTESCAPE	(1 << 4)
+
 /* Call return flags.  */
 /* Mask for the argument number that is returned.  Lower two bits of
    the return flags, encodes argument slots zero to three.  */
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index a4832b75436..9f4de96d544 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -3851,6 +3851,23 @@ make_escape_constraint (tree op)
   make_constraint_to (escaped_id, op);
 }
 
+/* Make constraint necessary to make all indirect references
+   from VI escape.  */
+
+static void
+make_indirect_escape_constraint (varinfo_t vi)
+{
+  struct constraint_expr lhs, rhs;
+  /* escaped = *(VAR + UNKNOWN);  */
+  lhs.type = SCALAR;
+  lhs.var = escaped_id;
+  lhs.offset = 0;
+  rhs.type = DEREF;
+  rhs.var = vi->id;
+  rhs.offset = UNKNOWN_OFFSET;
+  process_constraint (new_constraint (lhs, rhs));
+}
+
 /* Add constraints to that the solution of VI is transitively closed.  */
 
 static void
@@ -4026,7 +4043,7 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results)
 	 set.  The argument would still get clobbered through the
 	 escape solution.  */
       if ((flags & EAF_NOCLOBBER)
-	   && (flags & EAF_NOESCAPE))
+	   && (flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE)))
 	{
 	  varinfo_t uses = get_call_use_vi (stmt);
 	  varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
@@ -4036,9 +4053,11 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results)
 	  if (!(flags & EAF_DIRECT))
 	    make_transitive_closure_constraints (tem);
 	  make_copy_constraint (uses, tem->id);
+	  if (!(flags & (EAF_NOESCAPE | EAF_DIRECT)))
+	    make_indirect_escape_constraint (tem);
 	  returns_uses = true;
 	}
-      else if (flags & EAF_NOESCAPE)
+      else if (flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE))
 	{
 	  struct constraint_expr lhs, rhs;
 	  varinfo_t uses = get_call_use_vi (stmt);
@@ -4061,6 +4080,8 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results)
 	  rhs.var = nonlocal_id;
 	  rhs.offset = 0;
 	  process_constraint (new_constraint (lhs, rhs));
+	  if (!(flags & (EAF_NOESCAPE | EAF_DIRECT)))
+	    make_indirect_escape_constraint (tem);
 	  returns_uses = true;
 	}
       else
diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
index e6cb4a87b69..8305393e3ca 100644
--- a/gcc/ipa-modref.c
+++ b/gcc/ipa-modref.c
@@ -151,6 +151,8 @@ dump_eaf_flags (FILE *out, int flags, bool newline = true)
     fprintf (out, " noclobber");
   if (flags & EAF_NOESCAPE)
     fprintf (out, " noescape");
+  if (flags & EAF_NODIRECTESCAPE)
+    fprintf (out, " nodirectescape");
   if (flags & EAF_UNUSED)
     fprintf (out, " unused");
   if (newline)
@@ -1303,7 +1305,7 @@ memory_access_to (tree op, tree ssa_name)
 static int
 deref_flags (int flags, bool ignore_stores)
 {
-  int ret = 0;
+  int ret = EAF_NODIRECTESCAPE;
   if (flags & EAF_UNUSED)
     ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE;
   else
@@ -1361,7 +1363,8 @@ public:
 void
 modref_lattice::init ()
 {
-  flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED;
+  flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
+	  | EAF_NODIRECTESCAPE;
   open = true;
   known = false;
 }
@@ -1653,7 +1656,8 @@ analyze_ssa_name_flags (tree name, vec<modref_lattice> &lattice, int depth,
 		      {
 			int call_flags = gimple_call_arg_flags (call, i);
 			if (ignore_stores)
-			  call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
+			  call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE
+					| EAF_NODIRECTESCAPE;
 
 			if (!record_ipa)
 			  lattice[index].merge (call_flags);
@@ -1829,7 +1833,7 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
       /* For pure functions we have implicit NOCLOBBER
 	 and NOESCAPE.  */
       if (ecf_flags & ECF_PURE)
-	flags &= ~(EAF_NOCLOBBER | EAF_NOESCAPE);
+	flags &= ~(EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE);
 
       if (flags)
 	{
@@ -3098,7 +3102,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
 	    if (!ee->direct)
 	      flags = deref_flags (flags, ignore_stores);
 	    else if (ignore_stores)
-	      flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
+	      flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE;
 	    flags |= ee->min_flags;
 	    to_info->arg_flags[ee->parm_index] &= flags;
 	    if (to_info->arg_flags[ee->parm_index])
@@ -3112,7 +3116,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
 	    if (!ee->direct)
 	      flags = deref_flags (flags, ignore_stores);
 	    else if (ignore_stores)
-	      flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
+	      flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE;
 	    flags |= ee->min_flags;
 	    to_info_lto->arg_flags[ee->parm_index] &= flags;
 	    if (to_info_lto->arg_flags[ee->parm_index])
@@ -3623,8 +3627,8 @@ modref_merge_call_site_flags (escape_summary *sum,
 	}
       else if (ignore_stores)
 	{
-	  flags |= EAF_NOESCAPE | EAF_NOCLOBBER;
-	  flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER;
+	  flags |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE;
+	  flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE;
 	}
       flags |= ee->min_flags;
       flags_lto |= ee->min_flags;
