diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h
index 9dc8f88..9ec27ce 100644
--- a/include/clang/Analysis/Analyses/FormatString.h
+++ b/include/clang/Analysis/Analyses/FormatString.h
@@ -306,9 +306,9 @@ protected:
   LengthModifier LM;
   OptionalAmount FieldWidth;
   ConversionSpecifier CS;
-    /// Positional arguments, an IEEE extension:
-    ///  IEEE Std 1003.1, 2004 Edition
-    ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
+  /// Positional arguments, an IEEE extension:
+  ///  IEEE Std 1003.1, 2004 Edition
+  ///  http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
   bool UsesPositionalArg;
   unsigned argIndex;
 public:
@@ -598,6 +598,8 @@ public:
 
   virtual void HandleNullChar(const char *nullCharacter) {}
 
+  virtual void HandlePosition(const char *startPos, unsigned posLen) {}
+
   virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
                                      PositionContext p) {}
 
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index ec4604a..efa4fbf 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4853,6 +4853,8 @@ def warn_printf_nonsensical_flag: Warning<
 def warn_format_nonsensical_length: Warning<
   "length modifier '%0' results in undefined behavior or no effect with '%1' conversion specifier">,
   InGroup<Format>;
+def warn_format_non_standard_positional_arg: ExtWarn<
+  "positional arguments are non-standard">, InGroup<FormatNonStandard>, DefaultIgnore;
 def warn_format_non_standard: ExtWarn<
   "'%0' is a non-standard %1">, InGroup<FormatNonStandard>, DefaultIgnore;
 def warn_format_non_standard_conversion_spec: ExtWarn<
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index 5785655..dd2f240 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -156,6 +156,9 @@ clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
   }
 
   if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
+    // Warn that positional arguments are non-standard.
+    H.HandlePosition(Start, I - Start);
+
     // Special case: '%0$', since this is an easy mistake.
     if (Amt.getConstantAmount() == 0) {
       H.HandleZeroPosition(Start, I - Start);
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index e963065..67140b3 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -1677,6 +1677,8 @@ public:
       const analyze_format_string::ConversionSpecifier &CS,
       const char *startSpecifier, unsigned specifierLen);
 
+  virtual void HandlePosition(const char *startPos, unsigned posLen);
+
   virtual void HandleInvalidPosition(const char *startSpecifier,
                                      unsigned specifierLen,
                                      analyze_format_string::PositionContext p);
@@ -1783,6 +1785,14 @@ void CheckFormatHandler::HandleNonStandardConversionSpecification(
                        getSpecifierRange(startSpecifier, specifierLen));
 }
 
+void CheckFormatHandler::HandlePosition(const char *startPos,
+                                        unsigned posLen) {
+  EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard_positional_arg),
+                               getLocationOfByte(startPos),
+                               /*IsStringLocation*/true,
+                               getSpecifierRange(startPos, posLen));
+}
+
 void
 CheckFormatHandler::HandleInvalidPosition(const char *startPos, unsigned posLen,
                                      analyze_format_string::PositionContext p) {
diff --git a/test/Sema/format-strings-fixit.c b/test/Sema/format-strings-fixit.c
index 80b1be0..31afe3c 100644
--- a/test/Sema/format-strings-fixit.c
+++ b/test/Sema/format-strings-fixit.c
@@ -35,7 +35,10 @@ void test() {
   printf("%0-f", 1.23); // - flag should stay
 
   // Positional arguments
+#pragma clang diagnostic push // Don't warn about using positional arguments.
+#pragma clang diagnostic ignored "-Wformat-non-standard"
   printf("%1$f:%2$.*3$f:%4$.*3$f\n", 1, 2, 3, 4);
+#pragma clang diagnostic pop
 
   // Precision
   printf("%10.5d", 1l); // (bug 7394)
@@ -46,7 +49,10 @@ void test() {
 
   // Bad length modifiers
   printf("%hhs", "foo");
+#pragma clang diagnostic push // Don't warn about using positional arguments.
+#pragma clang diagnostic ignored "-Wformat-non-standard"
   printf("%1$zp", (void *)0);
+#pragma clang diagnostic pop
 
   // Preserve the original formatting for unsigned integers.
   unsigned long val = 42;
diff --git a/test/Sema/format-strings-non-standard.c b/test/Sema/format-strings-non-standard.c
index a24d43a..05545af 100644
--- a/test/Sema/format-strings-non-standard.c
+++ b/test/Sema/format-strings-non-standard.c
@@ -23,4 +23,7 @@ void f(void) {
   printf("%Lu", (long long)42); // expected-warning{{using the length modifier 'L' with the conversion specifier 'u' is non-standard}}
   printf("%Lx", (long long)42); // expected-warning{{using the length modifier 'L' with the conversion specifier 'x' is non-standard}}
   printf("%LX", (long long)42); // expected-warning{{using the length modifier 'L' with the conversion specifier 'X' is non-standard}}
+
+  // Positional arguments.
+  printf("%1$d", 42); // expected-warning{{positional arguments are non-standard}}
 }
