Support the 'a' length modifier in scanf format strings as a C90
extension.

This fixes gcc.dg/format/c90-scanf-3.c and ext-4.c (test for excess
errors).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146649 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index 2d56c23..bbc6f07 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "FormatStringParsing.h"
+#include "clang/Basic/LangOptions.h"
 
 using clang::analyze_format_string::ArgTypeResult;
 using clang::analyze_format_string::FormatStringHandler;
@@ -175,7 +176,9 @@
 bool
 clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
                                                   const char *&I,
-                                                  const char *E) {
+                                                  const char *E,
+                                                  const LangOptions &LO,
+                                                  bool IsScanf) {
   LengthModifier::Kind lmKind = LengthModifier::None;
   const char *lmPosition = I;
   switch (*I) {
@@ -196,6 +199,19 @@
     case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;
     case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
     case 'q': lmKind = LengthModifier::AsLongLong;   ++I; break;
+    case 'a':
+      if (IsScanf && !LO.C99 && !LO.CPlusPlus) {
+        // For scanf in C90, look at the next character to see if this should
+        // be parsed as the GNU extension 'a' length modifier. If not, this
+        // will be parsed as a conversion specifier.
+        ++I;
+        if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {
+          lmKind = LengthModifier::AsAllocate;
+          break;
+        }
+        --I;
+      }
+      return false;
   }
   LengthModifier lm(lmPosition, lmKind);
   FS.setLengthModifier(lm);
@@ -391,6 +407,8 @@
     return "t";
   case AsLongDouble:
     return "L";
+  case AsAllocate:
+    return "a";
   case None:
     return "";
   }
@@ -527,6 +545,15 @@
         default:
           return false;
       }
+
+    case LengthModifier::AsAllocate:
+      switch (CS.getKind()) {
+        case ConversionSpecifier::sArg:
+        case ConversionSpecifier::SArg:
+          return true;
+        default:
+          return false;
+      }
   }
   return false;
 }