--- gcc/tree.h.jj	2014-01-07 17:49:40.000000000 +0100
+++ gcc/tree.h	2014-01-20 15:04:48.273418236 +0100
@@ -5854,12 +5854,14 @@ extern tree fold_call_expr (location_t,
 extern tree fold_builtin_fputs (location_t, tree, tree, bool, bool, tree);
 extern tree fold_builtin_strcpy (location_t, tree, tree, tree, tree);
 extern tree fold_builtin_strncpy (location_t, tree, tree, tree, tree, tree);
+extern tree fold_builtin_strcat (location_t, tree, tree, tree);
 extern tree fold_builtin_memory_chk (location_t, tree, tree, tree, tree, tree, tree, bool,
 				     enum built_in_function);
 extern tree fold_builtin_stxcpy_chk (location_t, tree, tree, tree, tree, tree, bool,
 				     enum built_in_function);
 extern tree fold_builtin_stxncpy_chk (location_t, tree, tree, tree, tree, tree, bool,
 				      enum built_in_function);
+extern tree fold_builtin_strcat_chk (location_t, tree, tree, tree, tree, tree);
 extern tree fold_builtin_snprintf_chk (location_t, tree, tree, enum built_in_function);
 extern bool fold_builtin_next_arg (tree, bool);
 extern enum built_in_function builtin_mathfn_code (const_tree);
--- gcc/builtins.c.jj	2014-01-20 12:41:48.000000000 +0100
+++ gcc/builtins.c	2014-01-20 15:19:23.585947825 +0100
@@ -180,7 +180,6 @@ static tree fold_builtin_varargs (locati
 static tree fold_builtin_strpbrk (location_t, tree, tree, tree);
 static tree fold_builtin_strstr (location_t, tree, tree, tree);
 static tree fold_builtin_strrchr (location_t, tree, tree, tree);
-static tree fold_builtin_strcat (location_t, tree, tree);
 static tree fold_builtin_strncat (location_t, tree, tree, tree);
 static tree fold_builtin_strspn (location_t, tree, tree);
 static tree fold_builtin_strcspn (location_t, tree, tree);
@@ -194,7 +193,6 @@ static void maybe_emit_chk_warning (tree
 static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
 static void maybe_emit_free_warning (tree);
 static tree fold_builtin_object_size (tree, tree);
-static tree fold_builtin_strcat_chk (location_t, tree, tree, tree, tree);
 static tree fold_builtin_strncat_chk (location_t, tree, tree, tree, tree, tree);
 static tree fold_builtin_sprintf_chk (location_t, tree, enum built_in_function);
 static tree fold_builtin_printf (location_t, tree, tree, tree, bool, enum built_in_function);
@@ -10770,7 +10768,7 @@ fold_builtin_2 (location_t loc, tree fnd
       return fold_builtin_strstr (loc, arg0, arg1, type);
 
     case BUILT_IN_STRCAT:
-      return fold_builtin_strcat (loc, arg0, arg1);
+      return fold_builtin_strcat (loc, arg0, arg1, NULL_TREE);
 
     case BUILT_IN_STRSPN:
       return fold_builtin_strspn (loc, arg0, arg1);
@@ -10963,7 +10961,8 @@ fold_builtin_3 (location_t loc, tree fnd
 				      ignore, fcode);
 
     case BUILT_IN_STRCAT_CHK:
-      return fold_builtin_strcat_chk (loc, fndecl, arg0, arg1, arg2);
+      return fold_builtin_strcat_chk (loc, fndecl, arg0, arg1,
+				      NULL_TREE, arg2);
 
     case BUILT_IN_PRINTF_CHK:
     case BUILT_IN_VPRINTF_CHK:
@@ -11813,8 +11812,9 @@ fold_builtin_strpbrk (location_t loc, tr
    COMPOUND_EXPR in the chain will contain the tree for the simplified
    form of the builtin function call.  */
 
-static tree
-fold_builtin_strcat (location_t loc ATTRIBUTE_UNUSED, tree dst, tree src)
+tree
+fold_builtin_strcat (location_t loc ATTRIBUTE_UNUSED, tree dst, tree src,
+		     tree len)
 {
   if (!validate_arg (dst, POINTER_TYPE)
       || !validate_arg (src, POINTER_TYPE))
@@ -11832,14 +11832,15 @@ fold_builtin_strcat (location_t loc ATTR
 	  /* See if we can store by pieces into (dst + strlen(dst)).  */
 	  tree newdst, call;
 	  tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN);
-	  tree strcpy_fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+	  tree memcpy_fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
 
-	  if (!strlen_fn || !strcpy_fn)
+	  if (!strlen_fn || !memcpy_fn)
 	    return NULL_TREE;
 
 	  /* If the length of the source string isn't computable don't
-	     split strcat into strlen and strcpy.  */
-	  tree len = c_strlen (src, 1);
+	     split strcat into strlen and memcpy.  */
+	  if (! len)
+	    len = c_strlen (src, 1);
 	  if (! len || TREE_SIDE_EFFECTS (len))
 	    return NULL_TREE;
 
@@ -11853,7 +11854,11 @@ fold_builtin_strcat (location_t loc ATTR
 	  newdst = fold_build_pointer_plus_loc (loc, dst, newdst);
 	  newdst = builtin_save_expr (newdst);
 
-	  call = build_call_expr_loc (loc, strcpy_fn, 2, newdst, src);
+	  len = fold_convert_loc (loc, size_type_node, len);
+	  len = size_binop_loc (loc, PLUS_EXPR, len,
+				build_int_cst (size_type_node, 1));
+
+	  call = build_call_expr_loc (loc, memcpy_fn, 3, newdst, src, len);
 	  return build2 (COMPOUND_EXPR, TREE_TYPE (dst), call, dst);
 	}
       return NULL_TREE;
@@ -13005,9 +13010,9 @@ fold_builtin_stxncpy_chk (location_t loc
 /* Fold a call to the __strcat_chk builtin FNDECL.  DEST, SRC, and SIZE
    are the arguments to the call.  */
 
-static tree
+tree
 fold_builtin_strcat_chk (location_t loc, tree fndecl, tree dest,
-			 tree src, tree size)
+			 tree src, tree len, tree size)
 {
   tree fn;
   const char *p;
@@ -13030,6 +13035,12 @@ fold_builtin_strcat_chk (location_t loc,
   if (!fn)
     return NULL_TREE;
 
+  if (len)
+    {
+      tree ret = fold_builtin_strcat (loc, dest, src, len);
+      if (ret)
+	return ret;
+    }
   return build_call_expr_loc (loc, fn, 2, dest, src);
 }
 
--- gcc/gimple-fold.c.jj	2013-11-05 13:06:02.000000000 +0100
+++ gcc/gimple-fold.c	2014-01-20 15:12:42.297991142 +0100
@@ -866,6 +866,8 @@ gimple_fold_builtin (gimple stmt)
       break;
     case BUILT_IN_STRCPY:
     case BUILT_IN_STRNCPY:
+    case BUILT_IN_STRCAT:
+    case BUILT_IN_STRCAT_CHK:
       arg_idx = 1;
       type = 0;
       break;
@@ -941,6 +943,22 @@ gimple_fold_builtin (gimple stmt)
 				       val[1]);
       break;
 
+    case BUILT_IN_STRCAT:
+      if (val[1] && is_gimple_val (val[1]) && nargs == 2)
+	result = fold_builtin_strcat (loc, gimple_call_arg (stmt, 0),
+                                      gimple_call_arg (stmt, 1),
+				      val[1]);
+      break;
+
+    case BUILT_IN_STRCAT_CHK:
+      if (val[1] && is_gimple_val (val[1]) && nargs == 3)
+	result = fold_builtin_strcat_chk (loc, callee,
+					  gimple_call_arg (stmt, 0),
+					  gimple_call_arg (stmt, 1),
+					  val[1],
+					  gimple_call_arg (stmt, 2));
+      break;
+
     case BUILT_IN_FPUTS:
       if (nargs == 2)
 	result = fold_builtin_fputs (loc, gimple_call_arg (stmt, 0),
