Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 186819)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -1787,8 +1787,9 @@
   "redeclaration has different alignment requirement (%1 vs %0)">;
 def err_alignas_underaligned : Error<
   "requested alignment is less than minimum alignment of %1 for type %0">;
-def err_attribute_first_argument_not_int_or_bool : Error<
-  "%0 attribute first argument must be of int or bool type">;
+def err_attribute_argument_n_type : Error<
+  "%0 attribute requires parameter %1 to be %select{int or bool|an integer "
+  "constant|a string|an identifier}2">;
 def err_attribute_argument_outof_range : Error<
   "init_priority attribute requires integer constant between "
   "101 and 65535 inclusive">;
@@ -1797,12 +1798,6 @@
   "of objects of class type">;
 def err_attribute_argument_vec_type_hint : Error<
   "invalid attribute argument %0 - expecting a vector or vectorizable scalar type">;
-def err_attribute_argument_n_not_int : Error<
-  "'%0' attribute requires parameter %1 to be an integer constant">;
-def err_attribute_argument_n_not_string : Error<
-  "'%0' attribute requires parameter %1 to be a string">;
-def err_attribute_argument_n_not_identifier : Error<
-  "'%0' attribute requires parameter %1 to be an identifier">;
 def err_attribute_argument_out_of_bounds : Error<
   "'%0' attribute parameter %1 is out of bounds">;
 def err_attribute_uuid_malformed_guid : Error<
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp	(revision 186819)
+++ lib/Sema/SemaDeclAttr.cpp	(working copy)
@@ -252,8 +252,9 @@
   llvm::APSInt IdxInt;
   if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
       !IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) {
-    S.Diag(AttrLoc, diag::err_attribute_argument_n_not_int)
-      << AttrName << AttrArgNum << IdxExpr->getSourceRange();
+    std::string Name = std::string("'") + AttrName.str() + std::string("'");
+    S.Diag(AttrLoc, diag::err_attribute_argument_n_type) << Name.c_str()
+      << AttrArgNum << 1 /*integer constant*/ << IdxExpr->getSourceRange();
     return false;
   }
 
@@ -832,8 +833,8 @@
   }
 
   if (!isIntOrBool(Attr.getArg(0))) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_first_argument_not_int_or_bool)
-      << Attr.getName();
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+      << Attr.getName() << 1 << 0 /*int or bool*/;
     return false;
   }
 
@@ -1324,8 +1325,8 @@
   // a list append function may well be __attribute((ownership_holds)).
 
   if (!AL.getParameterName()) {
-    S.Diag(AL.getLoc(), diag::err_attribute_argument_n_not_string)
-        << AL.getName()->getName() << 1;
+    S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
+        << AL.getName()->getName() << 1 << 2 /*string*/;
     return;
   }
   // Figure out our Kind, and check arguments while we're at it.
@@ -1530,8 +1531,8 @@
     StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
 
     if (!Str || !Str->isAscii()) {
-      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
-          << "weakref" << 1;
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+        << Attr.getName() << 1 << 2 /*string*/;
       return;
     }
     // GCC will accept anything as the argument of weakref. Should we
@@ -1555,8 +1556,8 @@
   StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
 
   if (!Str || !Str->isAscii()) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
-      << "alias" << 1;
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+      << Attr.getName() << 1 << 2 /*string*/;
     return;
   }
 
@@ -1985,8 +1986,9 @@
     llvm::APSInt Idx(32);
     if (E->isTypeDependent() || E->isValueDependent() ||
         !E->isIntegerConstantExpr(Idx, S.Context)) {
-      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
-        << "constructor" << 1 << E->getSourceRange();
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+        << Attr.getName() << 1 << 1 /*integer constant*/
+        << E->getSourceRange();
       return;
     }
     priority = Idx.getZExtValue();
@@ -2016,8 +2018,9 @@
     llvm::APSInt Idx(32);
     if (E->isTypeDependent() || E->isValueDependent() ||
         !E->isIntegerConstantExpr(Idx, S.Context)) {
-      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
-        << "destructor" << 1 << E->getSourceRange();
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+        << Attr.getName() << 1 << 1 /*integer constant*/
+        << E->getSourceRange();
       return;
     }
     priority = Idx.getZExtValue();
@@ -2387,8 +2390,8 @@
   StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
 
   if (!Str || !Str->isAscii()) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
-      << (isTypeVisibility ? "type_visibility" : "visibility") << 1;
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+      << Attr.getName() << 1 << 2 /*string*/;
     return;
   }
 
@@ -2439,8 +2442,8 @@
 
   if (Attr.getNumArgs() != 0 || !Attr.getParameterName()) {
     if (!Attr.getParameterName() && Attr.getNumArgs() == 1) {
-      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
-        << "objc_method_family" << 1;
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+        << Attr.getName() << 1 << 2 /*string*/;
     } else {
       S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
     }
@@ -2550,8 +2553,8 @@
 
 static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   if (!Attr.getParameterName()) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
-      << "blocks" << 1;
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+      << Attr.getName() << 1 << 2 /*string*/;
     return;
   }
 
@@ -2587,8 +2590,9 @@
     llvm::APSInt Idx(32);
     if (E->isTypeDependent() || E->isValueDependent() ||
         !E->isIntegerConstantExpr(Idx, S.Context)) {
-      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
-       << "sentinel" << 1 << E->getSourceRange();
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+       << Attr.getName() << 1 << 1 /*integer constant*/
+       << E->getSourceRange();
       return;
     }
 
@@ -2607,8 +2611,9 @@
     llvm::APSInt Idx(32);
     if (E->isTypeDependent() || E->isValueDependent() ||
         !E->isIntegerConstantExpr(Idx, S.Context)) {
-      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
-        << "sentinel" << 2 << E->getSourceRange();
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+        << Attr.getName() << 2 << 1 /*integer constant*/
+        << E->getSourceRange();
       return;
     }
     nullPos = Idx.getZExtValue();
@@ -3034,8 +3039,9 @@
   llvm::APSInt Idx(32);
   if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
       !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
-    << "format" << 2 << IdxExpr->getSourceRange();
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+    << Attr.getName() << 2 << 1 /*integer constant*/
+    << IdxExpr->getSourceRange();
     return;
   }
 
@@ -3192,8 +3198,8 @@
 static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
 
   if (!Attr.getParameterName()) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
-      << "format" << 1;
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+      << Attr.getName() << 1 << 2 /*string*/;
     return;
   }
 
@@ -3237,8 +3243,9 @@
   llvm::APSInt Idx(32);
   if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
       !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
-      << "format" << 2 << IdxExpr->getSourceRange();
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+      << Attr.getName() << 2 << 1 /*integer constant*/
+      << IdxExpr->getSourceRange();
     return;
   }
 
@@ -3292,8 +3299,9 @@
   llvm::APSInt FirstArg(32);
   if (FirstArgExpr->isTypeDependent() || FirstArgExpr->isValueDependent() ||
       !FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
-      << "format" << 3 << FirstArgExpr->getSourceRange();
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+      << Attr.getName() << 3 << 1 /*integer constant*/
+      << FirstArgExpr->getSourceRange();
     return;
   }
 
@@ -4089,8 +4097,8 @@
     Expr *Arg = attr.getArg(0);
     StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
     if (!Str || !Str->isAscii()) {
-      Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
-        << "pcs" << 1;
+      Diag(attr.getLoc(), diag::err_attribute_argument_n_type)
+        << attr.getName() << 1 << 2 /*string*/;
       attr.setInvalid();
       return true;
     }
@@ -4205,8 +4213,9 @@
     if (MaxThreadsExpr->isTypeDependent() ||
         MaxThreadsExpr->isValueDependent() ||
         !MaxThreadsExpr->isIntegerConstantExpr(MaxThreads, S.Context)) {
-      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
-        << "launch_bounds" << 1 << MaxThreadsExpr->getSourceRange();
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+        << Attr.getName() << 1 << 1 /*integer constant*/
+        << MaxThreadsExpr->getSourceRange();
       return;
     }
 
@@ -4216,8 +4225,9 @@
       if (MinBlocksExpr->isTypeDependent() ||
           MinBlocksExpr->isValueDependent() ||
           !MinBlocksExpr->isIntegerConstantExpr(MinBlocks, S.Context)) {
-        S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int)
-          << "launch_bounds" << 2 << MinBlocksExpr->getSourceRange();
+        S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+          << Attr.getName() << 2 << 1 /*integer constant*/
+          << MinBlocksExpr->getSourceRange();
         return;
       }
     }
@@ -4236,8 +4246,8 @@
                                           const AttributeList &Attr) {
   StringRef AttrName = Attr.getName()->getName();
   if (!Attr.getParameterName()) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_identifier)
-      << Attr.getName() << /* arg num = */ 1;
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+      << Attr.getName() << /* arg num = */ 1 << 3 /*identifier*/;
     return;
   }
 
@@ -4287,8 +4297,8 @@
                                          const AttributeList &Attr) {
   IdentifierInfo *PointerKind = Attr.getParameterName();
   if (!PointerKind) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_identifier)
-      << "type_tag_for_datatype" << 1;
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+      << Attr.getName() << 1 << 3 /*identifier*/;
     return;
   }
 
@@ -4645,8 +4655,8 @@
   Expr *Arg = Attr.getArg(0);
   StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
   if (!Str || !Str->isAscii()) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
-      << "uuid" << 1;
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+      << Attr.getName() << 1 << 2 /*string*/;
     return;
   }
 
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp	(revision 186819)
+++ lib/Sema/SemaType.cpp	(working copy)
@@ -3936,8 +3936,8 @@
     AttrLoc = S.getSourceManager().getImmediateExpansionRange(AttrLoc).first;
 
   if (!attr.getParameterName()) {
-    S.Diag(AttrLoc, diag::err_attribute_argument_n_not_string)
-      << "objc_ownership" << 1;
+    S.Diag(AttrLoc, diag::err_attribute_argument_n_type)
+      << attr.getName() << 1 << 2 /*string*/;
     attr.setInvalid();
     return true;
   }
@@ -4072,8 +4072,8 @@
 
   // Check the attribute arguments.
   if (!attr.getParameterName()) {
-    S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
-      << "objc_gc" << 1;
+    S.Diag(attr.getLoc(), diag::err_attribute_argument_n_type)
+      << attr.getName() << 1 << 2 /*string*/;
     attr.setInvalid();
     return true;
   }
Index: test/SemaCXX/warn-thread-safety-parsing.cpp
===================================================================
--- test/SemaCXX/warn-thread-safety-parsing.cpp	(revision 186819)
+++ test/SemaCXX/warn-thread-safety-parsing.cpp	(working copy)
@@ -760,11 +760,11 @@
 
 // illegal attribute arguments
 int etf_function_bad_1() EXCLUSIVE_TRYLOCK_FUNCTION(mu1); // \
-  // expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+  // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be int or bool}}
 int etf_function_bad_2() EXCLUSIVE_TRYLOCK_FUNCTION("mu"); // \
-  // expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+  // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be int or bool}}
 int etf_function_bad_3() EXCLUSIVE_TRYLOCK_FUNCTION(muDoublePointer); // \
-  // expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+  // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be int or bool}}
 
 int etf_function_bad_4() EXCLUSIVE_TRYLOCK_FUNCTION(1, "mu"); // \
   // expected-warning {{ignoring 'exclusive_trylock_function' attribute because its argument is invalid}}
@@ -834,11 +834,11 @@
 
 // illegal attribute arguments
 int stf_function_bad_1() SHARED_TRYLOCK_FUNCTION(mu1); // \
-  // expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+  // expected-error {{'shared_trylock_function' attribute requires parameter 1 to be int or bool}}
 int stf_function_bad_2() SHARED_TRYLOCK_FUNCTION("mu"); // \
-  // expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+  // expected-error {{'shared_trylock_function' attribute requires parameter 1 to be int or bool}}
 int stf_function_bad_3() SHARED_TRYLOCK_FUNCTION(muDoublePointer); // \
-  // expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+  // expected-error {{'shared_trylock_function' attribute requires parameter 1 to be int or bool}}
 
 int stf_function_bad_4() SHARED_TRYLOCK_FUNCTION(1, "mu"); // \
   // expected-warning {{ignoring 'shared_trylock_function' attribute because its argument is invalid}}
Index: test/SemaObjC/method-sentinel-attr.m
===================================================================
--- test/SemaObjC/method-sentinel-attr.m	(revision 186819)
+++ test/SemaObjC/method-sentinel-attr.m	(working copy)
@@ -10,7 +10,7 @@
 - (void) foo5 : (int)x, ... __attribute__ ((__sentinel__(1))); // expected-note {{method has been explicitly marked sentinel here}}
 - (void) foo6 : (int)x, ... __attribute__ ((__sentinel__(5))); // expected-note {{method has been explicitly marked sentinel here}}
 - (void) foo7 : (int)x, ... __attribute__ ((__sentinel__(0))); // expected-note {{method has been explicitly marked sentinel here}}
-- (void) foo8 : (int)x, ... __attribute__ ((__sentinel__("a")));  // expected-error {{'sentinel' attribute requires parameter 1 to be an integer constant}}
+- (void) foo8 : (int)x, ... __attribute__ ((__sentinel__("a")));  // expected-error {{'__sentinel__' attribute requires parameter 1 to be an integer constant}}
 - (void) foo9 : (int)x, ... __attribute__ ((__sentinel__(-1)));  // expected-error {{'sentinel' parameter 1 less than zero}}
 - (void) foo10 : (int)x, ... __attribute__ ((__sentinel__(1,1)));
 - (void) foo11 : (int)x, ... __attribute__ ((__sentinel__(1,1,3)));  // expected-error {{attribute takes no more than 2 arguments}}
