--- gcc/builtins.c	(revision 166917)
+++ gcc/builtins.c	(revision 166918)
@@ -12537,15 +12537,30 @@ fold_builtin_printf (location_t loc, tre
 	{
 	  /* If the string was "string\n", call puts("string").  */
 	  size_t len = strlen (str);
-	  if ((unsigned char)str[len - 1] == target_newline)
+	  if ((unsigned char)str[len - 1] == target_newline
+	      && (size_t) (int) len == len
+	      && (int) len > 0)
 	    {
+	      char *newstr;
+	      tree offset_node, string_cst;
+
 	      /* Create a NUL-terminated string that's one char shorter
 		 than the original, stripping off the trailing '\n'.  */
-	      char *newstr = XALLOCAVEC (char, len);
-	      memcpy (newstr, str, len - 1);
-	      newstr[len - 1] = 0;
-
-	      newarg = build_string_literal (len, newstr);
+	      newarg = build_string_literal (len, str);
+	      string_cst = string_constant (newarg, &offset_node);
+#ifdef ENABLE_CHECKING
+	      gcc_assert (string_cst
+			  && (TREE_STRING_LENGTH (string_cst)
+			      == (int) len)
+			  && integer_zerop (offset_node)
+			  && (unsigned char)
+			      TREE_STRING_POINTER (string_cst)[len - 1]
+			      == target_newline);
+#endif
+	      /* build_string_literal creates a new STRING_CST,
+		 modify it in place to avoid double copying.  */
+	      newstr = CONST_CAST (char *, TREE_STRING_POINTER (string_cst));
+	      newstr[len - 1] = '\0';
 	      if (fn_puts)
 		call = build_call_expr_loc (loc, fn_puts, 1, newarg);
 	    }
--- gcc/testsuite/gcc.c-torture/compile/pr46534.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/compile/pr46534.c	(revision 166918)
@@ -0,0 +1,17 @@
+/* PR middle-end/46534 */
+
+extern int printf (const char *, ...);
+
+#define S1 "                    "
+#define S2 S1 S1 S1 S1 S1 S1 S1 S1 S1 S1
+#define S3 S2 S2 S2 S2 S2 S2 S2 S2 S2 S2
+#define S4 S3 S3 S3 S3 S3 S3 S3 S3 S3 S3
+#define S5 S4 S4 S4 S4 S4 S4 S4 S4 S4 S4
+#define S6 S5 S5 S5 S5 S5 S5 S5 S5 S5 S5
+#define S7 S6 S6 S6 S6 S6 S6 S6 S6 S6 S6
+
+void
+foo (void)
+{
+  printf (S7 "\n");
+}
