diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 72fba56..8c748e9 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1503,6 +1503,8 @@ extern void c_do_switch_warnings (splay_tree, location_t, tree, tree, bool,
 				  bool);
 extern void warn_for_omitted_condop (location_t, tree);
 extern void warn_for_restrict (unsigned, vec<tree, va_gc> *);
+extern void maybe_warn_string_plus_int (location_t, tree, tree,
+                                        enum tree_code, enum tree_code);
 
 /* Places where an lvalue, or modifiable lvalue, may be required.
    Used to select diagnostic messages in lvalue_error and
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 09c5760..0b038a7 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -2290,3 +2290,37 @@ do_warn_duplicated_branches_r (tree *tp, int *, void *)
     do_warn_duplicated_branches (*tp);
   return NULL_TREE;
 }
+
+static inline bool
+char_type_cv_p (tree type)
+{
+  return char_type_p (build_qualified_type (type, TYPE_UNQUALIFIED));
+}
+
+/* Warn about adding string literals/pointers and chars.
+   Produce a warning when:
+     1) arg1 is a string literal, and arg2 is a non-literal integer;
+     2) arg1 is a string pointer, and arg2 is a character.  */
+
+void
+maybe_warn_string_plus_int (location_t loc, tree type1, tree type2,
+                            enum tree_code code1, enum tree_code code2)
+{
+  bool arg2_is_char = char_type_cv_p (type2);
+  /* In C11, char16_t and char32_t are typedefs. Prevent false positives
+     about uint_least16_t and uint_least32_t.  */
+  if (type2 == uint_least16_type_node ||
+  	  type2 == uint_least32_type_node)
+  	arg2_is_char = false;
+
+  if (code1 == STRING_CST && TREE_CODE (type2) == INTEGER_TYPE &&
+      (code2 != INTEGER_CST || arg2_is_char))
+    warning_at (loc, OPT_Wstring_plus_int,
+                "adding %qT to string literal does not append to "
+                "the string", type2);
+  else if (TREE_CODE (type1) == POINTER_TYPE &&
+  	       char_type_cv_p (TREE_TYPE (type1)) && arg2_is_char)
+    warning_at (loc, OPT_Wstring_plus_int,
+                "adding %qT to string pointer %qT does not append "
+                "to the string", type2, type1);
+}
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index a1b3ae5..f0b482f 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -716,6 +716,11 @@ C ObjC C++ ObjC++ Joined RejectNegative UInteger Var(warn_stringop_overflow) Ini
 Under the control of Object Size type, warn about buffer overflow in string
 manipulation functions like memcpy and strcpy.
 
+Wstring-plus-int
+C ObjC C++ ObjC++ Var(warn_string_plus_int) Warning
+Warn about adding string pointers and integers, which is likely an ill-formed attempt
+to append the string.
+
 Wsuggest-attribute=format
 C ObjC C++ ObjC++ Var(warn_suggest_attribute_format) Warning
 Warn about functions which might be candidates for format attributes.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 93fae0d..95bda1b 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5555,6 +5555,8 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
   void *p;
   bool strict_p;
   bool any_viable_p;
+  tree orig_arg1 = error_mark_node;
+  tree orig_arg2 = error_mark_node;
 
   if (error_operand_p (arg1)
       || error_operand_p (arg2)
@@ -5605,8 +5607,20 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
       code_orig_arg2 = TREE_CODE (TREE_TYPE (arg2));
       break;
 
+    case PLUS_EXPR:
+      /* These are saved for the sake of warn_string_plus_int.  */
+      orig_arg1 = arg1;
+      orig_arg2 = arg2;
+      break;
+
       /* =, ->, [], () must be non-static member functions.  */
     case MODIFY_EXPR:
+      if (code2 == PLUS_EXPR)
+        {
+      	  /* Like PLUS_EXPR.  */
+      	  orig_arg1 = arg1;
+	  orig_arg2 = arg2;
+        }
       if (code2 != NOP_EXPR)
 	break;
       /* FALLTHRU */
@@ -5937,9 +5951,30 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
     return result;
 
  builtin:
+  /* Warn about adding string literals/pointers and chars.  */
+  if (code == PLUS_EXPR && (complain & tf_warning) &&
+      warn_string_plus_int)
+    {
+      maybe_warn_string_plus_int (loc, TREE_TYPE (arg1),
+				  TREE_TYPE (orig_arg2),
+				  TREE_CODE (arg1),
+				  TREE_CODE (orig_arg2));
+      maybe_warn_string_plus_int (loc, TREE_TYPE (arg2),
+				  TREE_TYPE (orig_arg1),
+				  TREE_CODE (arg2),
+				  TREE_CODE (orig_arg1));
+    }
+
   switch (code)
     {
     case MODIFY_EXPR:
+      /* Warn about adding string literals/pointers and chars.  */
+      if (code2 == PLUS_EXPR && (complain & tf_warning) &&
+      	  warn_string_plus_int)
+      	maybe_warn_string_plus_int (loc, TREE_TYPE (arg1),
+      	                            TREE_TYPE (orig_arg2),
+      	                            TREE_CODE (arg1),
+      	                            TREE_CODE (orig_arg2));
       return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
 
     case INDIRECT_REF:
