Index: test/Sema/builtins.c
===================================================================
--- test/Sema/builtins.c	(revision 150418)
+++ test/Sema/builtins.c	(working copy)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -triple=i686-apple-darwin9
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wno-string-plus-int -triple=i686-apple-darwin9
 // This test needs to set the target because it uses __builtin_ia32_vec_ext_v4si
 
 int test1(float a, int b) {
Index: test/SemaCXX/constant-expression-cxx11.cpp
===================================================================
--- test/SemaCXX/constant-expression-cxx11.cpp	(revision 150418)
+++ test/SemaCXX/constant-expression-cxx11.cpp	(working copy)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-linux -fsyntax-only -verify -std=c++11 -pedantic %s -Wno-comment
+// RUN: %clang_cc1 -triple i686-linux -Wno-string-plus-int -fsyntax-only -verify -std=c++11 -pedantic %s -Wno-comment
 
 namespace StaticAssertFoldTest {
 
Index: test/SemaCXX/null_in_arithmetic_ops.cpp
===================================================================
--- test/SemaCXX/null_in_arithmetic_ops.cpp	(revision 150418)
+++ test/SemaCXX/null_in_arithmetic_ops.cpp	(working copy)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -fblocks -Wnull-arithmetic -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -fblocks -Wnull-arithmetic -verify -Wno-string-plus-int %s
 #include <stddef.h>
 
 void f() {
Index: test/SemaCXX/array-bounds-ptr-arith.cpp
===================================================================
--- test/SemaCXX/array-bounds-ptr-arith.cpp	(revision 150418)
+++ test/SemaCXX/array-bounds-ptr-arith.cpp	(working copy)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -Warray-bounds-pointer-arithmetic %s
+// RUN: %clang_cc1 -verify -Wno-string-plus-int -Warray-bounds-pointer-arithmetic %s
 
 void swallow (const char *x) { (void)x; }
 void test_pointer_arithmetic(int n) {
Index: test/SemaCXX/string-plus-int.cpp
===================================================================
--- test/SemaCXX/string-plus-int.cpp	(revision 0)
+++ test/SemaCXX/string-plus-int.cpp	(revision 0)
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple i686-linux -fsyntax-only -verify %s
+
+void consume(const char* c) {}
+
+void f(int i) {
+  // Should warn.
+  consume("foo" + 3);  // expected-warning {{Adding an integral to a string does not append to the string}} expected-note {{use &(str[index]) if pointer arithmetic is intended}}
+  consume("foo" + i);  // expected-warning {{Adding an integral to a string does not append to the string}} expected-note {{use &(str[index]) if pointer arithmetic is intended}}
+
+  // Should not warn.
+  consume(&("foo"[3]));
+  consume(&("foo"[i]));
+}
+
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td	(revision 150418)
+++ include/clang/Basic/DiagnosticGroups.td	(working copy)
@@ -159,6 +159,7 @@
 def : DiagGroup<"switch-default">;
 def : DiagGroup<"synth">;
 def SizeofArrayArgument : DiagGroup<"sizeof-array-argument">;
+def StringPlusInt : DiagGroup<"string-plus-int">;
 def StrncatSize : DiagGroup<"strncat-size">;
 def TautologicalCompare : DiagGroup<"tautological-compare">;
 def HeaderHygiene : DiagGroup<"header-hygiene">;
@@ -320,6 +321,7 @@
     ReturnType,
     SelfAssignment,
     SizeofArrayArgument,
+    StringPlusInt,
     Trigraphs,
     Uninitialized,
     UnknownPragmas,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 150418)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -3414,6 +3414,12 @@
   "explicitly assigning a variable of type %0 to itself">,
   InGroup<SelfAssignment>, DefaultIgnore;
 
+def warn_string_plus_int : Warning<
+  "Adding an integral to a string does not append to the string">,
+  InGroup<StringPlusInt>;
+def note_string_plus_int_silence : Note<
+  "use &(str[index]) if pointer arithmetic is intended">;
+
 def warn_sizeof_array_param : Warning<
   "sizeof on array function parameter will return size of %0 instead of %1">,
   InGroup<SizeofArrayArgument>;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp	(revision 150418)
+++ lib/Sema/SemaExpr.cpp	(working copy)
@@ -7798,6 +7798,20 @@
     ParensRange);
 }
 
+/// DiagnoseStringPlusInt - Emit a warning when adding an integer to a string
+/// literal.
+static void DiagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc,
+                                  Expr *LHSExpr, Expr *RHSExpr) {
+  bool IsStringPlusInt = dyn_cast<StringLiteral>(LHSExpr) &&
+      RHSExpr->getType()->isIntegralType(Self.getASTContext());
+  if (!IsStringPlusInt)
+    return;
+
+  SourceRange DiagRange(LHSExpr->getLocStart(), RHSExpr->getLocEnd());
+  Self.Diag(OpLoc, diag::warn_string_plus_int) << DiagRange;
+  Self.Diag(OpLoc, diag::note_string_plus_int_silence);
+}
+
 /// \brief It accepts a '&' expr that is inside a '|' one.
 /// Emit a diagnostic together with a fixit hint that wraps the '&' expression
 /// in parentheses.
@@ -7920,6 +7934,10 @@
   // Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0"
   DiagnoseBinOpPrecedence(*this, Opc, TokLoc, LHSExpr, RHSExpr);
 
+  // Diagnose "string literal" '+' int.
+  if (Opc == BO_Add)
+    DiagnoseStringPlusInt(*this, TokLoc, LHSExpr, RHSExpr);
+
   return BuildBinOp(S, TokLoc, Opc, LHSExpr, RHSExpr);
 }
 
