r345971 - Reapply Logging: make os_log buffer size an integer constant expression.

Tim Northover via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 2 06:14:11 PDT 2018


Author: tnorthover
Date: Fri Nov  2 06:14:11 2018
New Revision: 345971

URL: http://llvm.org/viewvc/llvm-project?rev=345971&view=rev
Log:
Reapply Logging: make os_log buffer size an integer constant expression.

The size of an os_log buffer is known at any stage of compilation, so making it
a constant expression means that the common idiom of declaring a buffer for it
won't result in a VLA. That allows the compiler to skip saving and restoring
the stack pointer around such buffers.

This also moves the OSLog and other FormatString helpers from
libclangAnalysis to libclangAST to avoid a circular dependency.

Added:
    cfe/trunk/include/clang/AST/FormatString.h
    cfe/trunk/include/clang/AST/OSLog.h
    cfe/trunk/lib/AST/FormatString.cpp
    cfe/trunk/lib/AST/FormatStringParsing.h
    cfe/trunk/lib/AST/OSLog.cpp
    cfe/trunk/lib/AST/PrintfFormatString.cpp
    cfe/trunk/lib/AST/ScanfFormatString.cpp
Removed:
    cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
    cfe/trunk/include/clang/Analysis/Analyses/OSLog.h
    cfe/trunk/lib/Analysis/FormatString.cpp
    cfe/trunk/lib/Analysis/FormatStringParsing.h
    cfe/trunk/lib/Analysis/OSLog.cpp
    cfe/trunk/lib/Analysis/PrintfFormatString.cpp
    cfe/trunk/lib/Analysis/ScanfFormatString.cpp
Modified:
    cfe/trunk/lib/AST/CMakeLists.txt
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/Analysis/CMakeLists.txt
    cfe/trunk/lib/CodeGen/CGBuiltin.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/CodeGen/builtins.c

Added: cfe/trunk/include/clang/AST/FormatString.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/FormatString.h?rev=345971&view=auto
==============================================================================
--- cfe/trunk/include/clang/AST/FormatString.h (added)
+++ cfe/trunk/include/clang/AST/FormatString.h Fri Nov  2 06:14:11 2018
@@ -0,0 +1,719 @@
+//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines APIs for analyzing the format strings of printf, fscanf,
+// and friends.
+//
+// The structure of format strings for fprintf are described in C99 7.19.6.1.
+//
+// The structure of format strings for fscanf are described in C99 7.19.6.2.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
+
+#include "clang/AST/CanonicalType.h"
+
+namespace clang {
+
+class TargetInfo;
+
+//===----------------------------------------------------------------------===//
+/// Common components of both fprintf and fscanf format strings.
+namespace analyze_format_string {
+
+/// Class representing optional flags with location and representation
+/// information.
+class OptionalFlag {
+public:
+  OptionalFlag(const char *Representation)
+      : representation(Representation), flag(false) {}
+  bool isSet() const { return flag; }
+  void set() { flag = true; }
+  void clear() { flag = false; }
+  void setPosition(const char *position) {
+    assert(position);
+    flag = true;
+    this->position = position;
+  }
+  const char *getPosition() const {
+    assert(position);
+    return position;
+  }
+  const char *toString() const { return representation; }
+
+  // Overloaded operators for bool like qualities
+  explicit operator bool() const { return flag; }
+  OptionalFlag& operator=(const bool &rhs) {
+    flag = rhs;
+    return *this;  // Return a reference to myself.
+  }
+private:
+  const char *representation;
+  const char *position;
+  bool flag;
+};
+
+/// Represents the length modifier in a format string in scanf/printf.
+class LengthModifier {
+public:
+  enum Kind {
+    None,
+    AsChar,       // 'hh'
+    AsShort,      // 'h'
+    AsLong,       // 'l'
+    AsLongLong,   // 'll'
+    AsQuad,       // 'q' (BSD, deprecated, for 64-bit integer types)
+    AsIntMax,     // 'j'
+    AsSizeT,      // 'z'
+    AsPtrDiff,    // 't'
+    AsInt32,      // 'I32' (MSVCRT, like __int32)
+    AsInt3264,    // 'I'   (MSVCRT, like __int3264 from MIDL)
+    AsInt64,      // 'I64' (MSVCRT, like __int64)
+    AsLongDouble, // 'L'
+    AsAllocate,   // for '%as', GNU extension to C90 scanf
+    AsMAllocate,  // for '%ms', GNU extension to scanf
+    AsWide,       // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
+    AsWideChar = AsLong // for '%ls', only makes sense for printf
+  };
+
+  LengthModifier()
+    : Position(nullptr), kind(None) {}
+  LengthModifier(const char *pos, Kind k)
+    : Position(pos), kind(k) {}
+
+  const char *getStart() const {
+    return Position;
+  }
+
+  unsigned getLength() const {
+    switch (kind) {
+      default:
+        return 1;
+      case AsLongLong:
+      case AsChar:
+        return 2;
+      case AsInt32:
+      case AsInt64:
+        return 3;
+      case None:
+        return 0;
+    }
+  }
+
+  Kind getKind() const { return kind; }
+  void setKind(Kind k) { kind = k; }
+
+  const char *toString() const;
+
+private:
+  const char *Position;
+  Kind kind;
+};
+
+class ConversionSpecifier {
+public:
+  enum Kind {
+    InvalidSpecifier = 0,
+    // C99 conversion specifiers.
+    cArg,
+    dArg,
+    DArg, // Apple extension
+    iArg,
+    IntArgBeg = dArg,
+    IntArgEnd = iArg,
+
+    oArg,
+    OArg, // Apple extension
+    uArg,
+    UArg, // Apple extension
+    xArg,
+    XArg,
+    UIntArgBeg = oArg,
+    UIntArgEnd = XArg,
+
+    fArg,
+    FArg,
+    eArg,
+    EArg,
+    gArg,
+    GArg,
+    aArg,
+    AArg,
+    DoubleArgBeg = fArg,
+    DoubleArgEnd = AArg,
+
+    sArg,
+    pArg,
+    nArg,
+    PercentArg,
+    CArg,
+    SArg,
+
+    // Apple extension: P specifies to os_log that the data being pointed to is
+    // to be copied by os_log. The precision indicates the number of bytes to
+    // copy.
+    PArg,
+
+    // ** Printf-specific **
+
+    ZArg, // MS extension
+
+    // Objective-C specific specifiers.
+    ObjCObjArg, // '@'
+    ObjCBeg = ObjCObjArg,
+    ObjCEnd = ObjCObjArg,
+
+    // FreeBSD kernel specific specifiers.
+    FreeBSDbArg,
+    FreeBSDDArg,
+    FreeBSDrArg,
+    FreeBSDyArg,
+
+    // GlibC specific specifiers.
+    PrintErrno, // 'm'
+
+    PrintfConvBeg = ObjCObjArg,
+    PrintfConvEnd = PrintErrno,
+
+    // ** Scanf-specific **
+    ScanListArg, // '['
+    ScanfConvBeg = ScanListArg,
+    ScanfConvEnd = ScanListArg
+  };
+
+  ConversionSpecifier(bool isPrintf = true)
+    : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
+      kind(InvalidSpecifier) {}
+
+  ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
+    : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
+
+  const char *getStart() const {
+    return Position;
+  }
+
+  StringRef getCharacters() const {
+    return StringRef(getStart(), getLength());
+  }
+
+  bool consumesDataArgument() const {
+    switch (kind) {
+      case PrintErrno:
+        assert(IsPrintf);
+        return false;
+      case PercentArg:
+        return false;
+      case InvalidSpecifier:
+        return false;
+      default:
+        return true;
+    }
+  }
+
+  Kind getKind() const { return kind; }
+  void setKind(Kind k) { kind = k; }
+  unsigned getLength() const {
+    return EndScanList ? EndScanList - Position : 1;
+  }
+  void setEndScanList(const char *pos) { EndScanList = pos; }
+
+  bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
+    kind == FreeBSDrArg || kind == FreeBSDyArg; }
+  bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
+  bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
+  bool isDoubleArg() const {
+    return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
+  }
+
+  const char *toString() const;
+
+  bool isPrintfKind() const { return IsPrintf; }
+
+  Optional<ConversionSpecifier> getStandardSpecifier() const;
+
+protected:
+  bool IsPrintf;
+  const char *Position;
+  const char *EndScanList;
+  Kind kind;
+};
+
+class ArgType {
+public:
+  enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
+              AnyCharTy, CStrTy, WCStrTy, WIntTy };
+
+  enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
+
+private:
+  const Kind K;
+  QualType T;
+  const char *Name = nullptr;
+  bool Ptr = false;
+
+  /// The TypeKind identifies certain well-known types like size_t and
+  /// ptrdiff_t.
+  enum class TypeKind { DontCare, SizeT, PtrdiffT };
+  TypeKind TK = TypeKind::DontCare;
+
+public:
+  ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
+  ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
+  ArgType(CanQualType T) : K(SpecificTy), T(T) {}
+
+  static ArgType Invalid() { return ArgType(InvalidTy); }
+  bool isValid() const { return K != InvalidTy; }
+
+  bool isSizeT() const { return TK == TypeKind::SizeT; }
+
+  bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
+
+  /// Create an ArgType which corresponds to the type pointer to A.
+  static ArgType PtrTo(const ArgType& A) {
+    assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
+    ArgType Res = A;
+    Res.Ptr = true;
+    return Res;
+  }
+
+  /// Create an ArgType which corresponds to the size_t/ssize_t type.
+  static ArgType makeSizeT(const ArgType &A) {
+    ArgType Res = A;
+    Res.TK = TypeKind::SizeT;
+    return Res;
+  }
+
+  /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
+  /// type.
+  static ArgType makePtrdiffT(const ArgType &A) {
+    ArgType Res = A;
+    Res.TK = TypeKind::PtrdiffT;
+    return Res;
+  }
+
+  MatchKind matchesType(ASTContext &C, QualType argTy) const;
+
+  QualType getRepresentativeType(ASTContext &C) const;
+
+  std::string getRepresentativeTypeName(ASTContext &C) const;
+};
+
+class OptionalAmount {
+public:
+  enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
+
+  OptionalAmount(HowSpecified howSpecified,
+                 unsigned amount,
+                 const char *amountStart,
+                 unsigned amountLength,
+                 bool usesPositionalArg)
+  : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
+  UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
+
+  OptionalAmount(bool valid = true)
+  : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
+  UsesPositionalArg(0), UsesDotPrefix(0) {}
+
+  bool isInvalid() const {
+    return hs == Invalid;
+  }
+
+  HowSpecified getHowSpecified() const { return hs; }
+  void setHowSpecified(HowSpecified h) { hs = h; }
+
+  bool hasDataArgument() const { return hs == Arg; }
+
+  unsigned getArgIndex() const {
+    assert(hasDataArgument());
+    return amt;
+  }
+
+  unsigned getConstantAmount() const {
+    assert(hs == Constant);
+    return amt;
+  }
+
+  const char *getStart() const {
+      // We include the . character if it is given.
+    return start - UsesDotPrefix;
+  }
+
+  unsigned getConstantLength() const {
+    assert(hs == Constant);
+    return length + UsesDotPrefix;
+  }
+
+  ArgType getArgType(ASTContext &Ctx) const;
+
+  void toString(raw_ostream &os) const;
+
+  bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
+  unsigned getPositionalArgIndex() const {
+    assert(hasDataArgument());
+    return amt + 1;
+  }
+
+  bool usesDotPrefix() const { return UsesDotPrefix; }
+  void setUsesDotPrefix() { UsesDotPrefix = true; }
+
+private:
+  const char *start;
+  unsigned length;
+  HowSpecified hs;
+  unsigned amt;
+  bool UsesPositionalArg : 1;
+  bool UsesDotPrefix;
+};
+
+
+class FormatSpecifier {
+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
+  bool UsesPositionalArg;
+  unsigned argIndex;
+public:
+  FormatSpecifier(bool isPrintf)
+    : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}
+
+  void setLengthModifier(LengthModifier lm) {
+    LM = lm;
+  }
+
+  void setUsesPositionalArg() { UsesPositionalArg = true; }
+
+  void setArgIndex(unsigned i) {
+    argIndex = i;
+  }
+
+  unsigned getArgIndex() const {
+    return argIndex;
+  }
+
+  unsigned getPositionalArgIndex() const {
+    return argIndex + 1;
+  }
+
+  const LengthModifier &getLengthModifier() const {
+    return LM;
+  }
+
+  const OptionalAmount &getFieldWidth() const {
+    return FieldWidth;
+  }
+
+  void setFieldWidth(const OptionalAmount &Amt) {
+    FieldWidth = Amt;
+  }
+
+  bool usesPositionalArg() const { return UsesPositionalArg; }
+
+  bool hasValidLengthModifier(const TargetInfo &Target) const;
+
+  bool hasStandardLengthModifier() const;
+
+  Optional<LengthModifier> getCorrectedLengthModifier() const;
+
+  bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
+
+  bool hasStandardLengthConversionCombination() const;
+
+  /// For a TypedefType QT, if it is a named integer type such as size_t,
+  /// assign the appropriate value to LM and return true.
+  static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
+};
+
+} // end analyze_format_string namespace
+
+//===----------------------------------------------------------------------===//
+/// Pieces specific to fprintf format strings.
+
+namespace analyze_printf {
+
+class PrintfConversionSpecifier :
+  public analyze_format_string::ConversionSpecifier  {
+public:
+  PrintfConversionSpecifier()
+    : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
+
+  PrintfConversionSpecifier(const char *pos, Kind k)
+    : ConversionSpecifier(true, pos, k) {}
+
+  bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
+  bool isDoubleArg() const { return kind >= DoubleArgBeg &&
+                                    kind <= DoubleArgEnd; }
+
+  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
+    return CS->isPrintfKind();
+  }
+};
+
+using analyze_format_string::ArgType;
+using analyze_format_string::LengthModifier;
+using analyze_format_string::OptionalAmount;
+using analyze_format_string::OptionalFlag;
+
+class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
+  OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
+  OptionalFlag IsLeftJustified; // '-'
+  OptionalFlag HasPlusPrefix; // '+'
+  OptionalFlag HasSpacePrefix; // ' '
+  OptionalFlag HasAlternativeForm; // '#'
+  OptionalFlag HasLeadingZeroes; // '0'
+  OptionalFlag HasObjCTechnicalTerm; // '[tt]'
+  OptionalFlag IsPrivate;            // '{private}'
+  OptionalFlag IsPublic;             // '{public}'
+  OptionalAmount Precision;
+public:
+  PrintfSpecifier()
+      : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
+        IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
+        HasAlternativeForm("#"), HasLeadingZeroes("0"),
+        HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public") {}
+
+  static PrintfSpecifier Parse(const char *beg, const char *end);
+
+    // Methods for incrementally constructing the PrintfSpecifier.
+  void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
+    CS = cs;
+  }
+  void setHasThousandsGrouping(const char *position) {
+    HasThousandsGrouping.setPosition(position);
+  }
+  void setIsLeftJustified(const char *position) {
+    IsLeftJustified.setPosition(position);
+  }
+  void setHasPlusPrefix(const char *position) {
+    HasPlusPrefix.setPosition(position);
+  }
+  void setHasSpacePrefix(const char *position) {
+    HasSpacePrefix.setPosition(position);
+  }
+  void setHasAlternativeForm(const char *position) {
+    HasAlternativeForm.setPosition(position);
+  }
+  void setHasLeadingZeros(const char *position) {
+    HasLeadingZeroes.setPosition(position);
+  }
+  void setHasObjCTechnicalTerm(const char *position) {
+    HasObjCTechnicalTerm.setPosition(position);
+  }
+  void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
+  void setIsPublic(const char *position) { IsPublic.setPosition(position); }
+  void setUsesPositionalArg() { UsesPositionalArg = true; }
+
+    // Methods for querying the format specifier.
+
+  const PrintfConversionSpecifier &getConversionSpecifier() const {
+    return cast<PrintfConversionSpecifier>(CS);
+  }
+
+  void setPrecision(const OptionalAmount &Amt) {
+    Precision = Amt;
+    Precision.setUsesDotPrefix();
+  }
+
+  const OptionalAmount &getPrecision() const {
+    return Precision;
+  }
+
+  bool consumesDataArgument() const {
+    return getConversionSpecifier().consumesDataArgument();
+  }
+
+  /// Returns the builtin type that a data argument
+  /// paired with this format specifier should have.  This method
+  /// will return null if the format specifier does not have
+  /// a matching data argument or the matching argument matches
+  /// more than one type.
+  ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
+
+  const OptionalFlag &hasThousandsGrouping() const {
+      return HasThousandsGrouping;
+  }
+  const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
+  const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
+  const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
+  const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
+  const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
+  const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
+  const OptionalFlag &isPrivate() const { return IsPrivate; }
+  const OptionalFlag &isPublic() const { return IsPublic; }
+  bool usesPositionalArg() const { return UsesPositionalArg; }
+
+  /// Changes the specifier and length according to a QualType, retaining any
+  /// flags or options. Returns true on success, or false when a conversion
+  /// was not successful.
+  bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
+               bool IsObjCLiteral);
+
+  void toString(raw_ostream &os) const;
+
+  // Validation methods - to check if any element results in undefined behavior
+  bool hasValidPlusPrefix() const;
+  bool hasValidAlternativeForm() const;
+  bool hasValidLeadingZeros() const;
+  bool hasValidSpacePrefix() const;
+  bool hasValidLeftJustified() const;
+  bool hasValidThousandsGroupingPrefix() const;
+
+  bool hasValidPrecision() const;
+  bool hasValidFieldWidth() const;
+};
+}  // end analyze_printf namespace
+
+//===----------------------------------------------------------------------===//
+/// Pieces specific to fscanf format strings.
+
+namespace analyze_scanf {
+
+class ScanfConversionSpecifier :
+    public analyze_format_string::ConversionSpecifier  {
+public:
+  ScanfConversionSpecifier()
+    : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
+
+  ScanfConversionSpecifier(const char *pos, Kind k)
+    : ConversionSpecifier(false, pos, k) {}
+
+  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
+    return !CS->isPrintfKind();
+  }
+};
+
+using analyze_format_string::ArgType;
+using analyze_format_string::LengthModifier;
+using analyze_format_string::OptionalAmount;
+using analyze_format_string::OptionalFlag;
+
+class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
+  OptionalFlag SuppressAssignment; // '*'
+public:
+  ScanfSpecifier() :
+    FormatSpecifier(/* isPrintf = */ false),
+    SuppressAssignment("*") {}
+
+  void setSuppressAssignment(const char *position) {
+    SuppressAssignment.setPosition(position);
+  }
+
+  const OptionalFlag &getSuppressAssignment() const {
+    return SuppressAssignment;
+  }
+
+  void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
+    CS = cs;
+  }
+
+  const ScanfConversionSpecifier &getConversionSpecifier() const {
+    return cast<ScanfConversionSpecifier>(CS);
+  }
+
+  bool consumesDataArgument() const {
+    return CS.consumesDataArgument() && !SuppressAssignment;
+  }
+
+  ArgType getArgType(ASTContext &Ctx) const;
+
+  bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
+               ASTContext &Ctx);
+
+  void toString(raw_ostream &os) const;
+
+  static ScanfSpecifier Parse(const char *beg, const char *end);
+};
+
+} // end analyze_scanf namespace
+
+//===----------------------------------------------------------------------===//
+// Parsing and processing of format strings (both fprintf and fscanf).
+
+namespace analyze_format_string {
+
+enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
+
+class FormatStringHandler {
+public:
+  FormatStringHandler() {}
+  virtual ~FormatStringHandler();
+
+  virtual void HandleNullChar(const char *nullCharacter) {}
+
+  virtual void HandlePosition(const char *startPos, unsigned posLen) {}
+
+  virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
+                                     PositionContext p) {}
+
+  virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
+
+  virtual void HandleIncompleteSpecifier(const char *startSpecifier,
+                                         unsigned specifierLen) {}
+
+  virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
+                                           unsigned flagsLen) {}
+
+  virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
+                                             unsigned flagLen) {}
+
+  virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
+                                            const char *flagsEnd,
+                                            const char *conversionPosition) {}
+  // Printf-specific handlers.
+
+  virtual bool HandleInvalidPrintfConversionSpecifier(
+                                      const analyze_printf::PrintfSpecifier &FS,
+                                      const char *startSpecifier,
+                                      unsigned specifierLen) {
+    return true;
+  }
+
+  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
+                                     const char *startSpecifier,
+                                     unsigned specifierLen) {
+    return true;
+  }
+
+    // Scanf-specific handlers.
+
+  virtual bool HandleInvalidScanfConversionSpecifier(
+                                        const analyze_scanf::ScanfSpecifier &FS,
+                                        const char *startSpecifier,
+                                        unsigned specifierLen) {
+    return true;
+  }
+
+  virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
+                                    const char *startSpecifier,
+                                    unsigned specifierLen) {
+    return true;
+  }
+
+  virtual void HandleIncompleteScanList(const char *start, const char *end) {}
+};
+
+bool ParsePrintfString(FormatStringHandler &H,
+                       const char *beg, const char *end, const LangOptions &LO,
+                       const TargetInfo &Target, bool isFreeBSDKPrintf);
+
+bool ParseFormatStringHasSArg(const char *beg, const char *end,
+                              const LangOptions &LO, const TargetInfo &Target);
+
+bool ParseScanfString(FormatStringHandler &H,
+                      const char *beg, const char *end, const LangOptions &LO,
+                      const TargetInfo &Target);
+
+} // end analyze_format_string namespace
+} // end clang namespace
+#endif

Added: cfe/trunk/include/clang/AST/OSLog.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OSLog.h?rev=345971&view=auto
==============================================================================
--- cfe/trunk/include/clang/AST/OSLog.h (added)
+++ cfe/trunk/include/clang/AST/OSLog.h Fri Nov  2 06:14:11 2018
@@ -0,0 +1,155 @@
+//= OSLog.h - Analysis of calls to os_log builtins --*- C++ -*-===============//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines APIs for determining the layout of the data buffer for
+// os_log() and os_trace().
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+
+namespace clang {
+namespace analyze_os_log {
+
+/// An OSLogBufferItem represents a single item in the data written by a call
+/// to os_log() or os_trace().
+class OSLogBufferItem {
+public:
+  enum Kind {
+    // The item is a scalar (int, float, raw pointer, etc.). No further copying
+    // is required. This is the only kind allowed by os_trace().
+    ScalarKind = 0,
+
+    // The item is a count, which describes the length of the following item to
+    // be copied. A count may only be followed by an item of kind StringKind,
+    // WideStringKind, or PointerKind.
+    CountKind,
+
+    // The item is a pointer to a C string. If preceded by a count 'n',
+    // os_log() will copy at most 'n' bytes from the pointer.
+    StringKind,
+
+    // The item is a pointer to a block of raw data. This item must be preceded
+    // by a count 'n'. os_log() will copy exactly 'n' bytes from the pointer.
+    PointerKind,
+
+    // The item is a pointer to an Objective-C object. os_log() may retain the
+    // object for later processing.
+    ObjCObjKind,
+
+    // The item is a pointer to wide-char string.
+    WideStringKind,
+
+    // The item is corresponding to the '%m' format specifier, no value is
+    // populated in the buffer and the runtime is loading the errno value.
+    ErrnoKind
+  };
+
+  enum {
+    // The item is marked "private" in the format string.
+    IsPrivate = 0x1,
+
+    // The item is marked "public" in the format string.
+    IsPublic = 0x2
+  };
+
+private:
+  Kind TheKind = ScalarKind;
+  const Expr *TheExpr = nullptr;
+  CharUnits ConstValue;
+  CharUnits Size; // size of the data, not including the header bytes
+  unsigned Flags = 0;
+
+public:
+  OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned flags)
+      : TheKind(kind), TheExpr(expr), Size(size), Flags(flags) {}
+
+  OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags)
+      : TheKind(CountKind), ConstValue(value),
+        Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {}
+
+  unsigned char getDescriptorByte() const {
+    unsigned char result = 0;
+    if (getIsPrivate())
+      result |= IsPrivate;
+    if (getIsPublic())
+      result |= IsPublic;
+    result |= ((unsigned)getKind()) << 4;
+    return result;
+  }
+
+  unsigned char getSizeByte() const { return size().getQuantity(); }
+
+  Kind getKind() const { return TheKind; }
+  bool getIsPrivate() const { return (Flags & IsPrivate) != 0; }
+  bool getIsPublic() const { return (Flags & IsPublic) != 0; }
+
+  const Expr *getExpr() const { return TheExpr; }
+  CharUnits getConstValue() const { return ConstValue; }
+  CharUnits size() const { return Size; }
+};
+
+class OSLogBufferLayout {
+public:
+  SmallVector<OSLogBufferItem, 4> Items;
+
+  enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 };
+
+  CharUnits size() const {
+    CharUnits result;
+    result += CharUnits::fromQuantity(2); // summary byte, num-args byte
+    for (auto &item : Items) {
+      // descriptor byte, size byte
+      result += item.size() + CharUnits::fromQuantity(2);
+    }
+    return result;
+  }
+
+  bool hasPrivateItems() const {
+    return llvm::any_of(
+        Items, [](const OSLogBufferItem &Item) { return Item.getIsPrivate(); });
+  }
+
+  bool hasPublicItems() const {
+    return llvm::any_of(
+        Items, [](const OSLogBufferItem &Item) { return Item.getIsPublic(); });
+  }
+
+  bool hasNonScalar() const {
+    return llvm::any_of(Items, [](const OSLogBufferItem &Item) {
+      return Item.getKind() != OSLogBufferItem::ScalarKind;
+    });
+  }
+
+  unsigned char getSummaryByte() const {
+    unsigned char result = 0;
+    if (hasPrivateItems())
+      result |= HasPrivateItems;
+    if (hasNonScalar())
+      result |= HasNonScalarItems;
+    return result;
+  }
+
+  unsigned char getNumArgsByte() const { return Items.size(); }
+};
+
+// Given a call 'E' to one of the builtins __builtin_os_log_format() or
+// __builtin_os_log_format_buffer_size(), compute the layout of the buffer that
+// the call will write into and store it in 'layout'. Returns 'false' if there
+// was some error encountered while computing the layout, and 'true' otherwise.
+bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const clang::CallExpr *E,
+                              OSLogBufferLayout &layout);
+
+} // namespace analyze_os_log
+} // namespace clang
+#endif

Removed: cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/FormatString.h?rev=345970&view=auto
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (removed)
@@ -1,719 +0,0 @@
-//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines APIs for analyzing the format strings of printf, fscanf,
-// and friends.
-//
-// The structure of format strings for fprintf are described in C99 7.19.6.1.
-//
-// The structure of format strings for fscanf are described in C99 7.19.6.2.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
-#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H
-
-#include "clang/AST/CanonicalType.h"
-
-namespace clang {
-
-class TargetInfo;
-
-//===----------------------------------------------------------------------===//
-/// Common components of both fprintf and fscanf format strings.
-namespace analyze_format_string {
-
-/// Class representing optional flags with location and representation
-/// information.
-class OptionalFlag {
-public:
-  OptionalFlag(const char *Representation)
-      : representation(Representation), flag(false) {}
-  bool isSet() const { return flag; }
-  void set() { flag = true; }
-  void clear() { flag = false; }
-  void setPosition(const char *position) {
-    assert(position);
-    flag = true;
-    this->position = position;
-  }
-  const char *getPosition() const {
-    assert(position);
-    return position;
-  }
-  const char *toString() const { return representation; }
-
-  // Overloaded operators for bool like qualities
-  explicit operator bool() const { return flag; }
-  OptionalFlag& operator=(const bool &rhs) {
-    flag = rhs;
-    return *this;  // Return a reference to myself.
-  }
-private:
-  const char *representation;
-  const char *position;
-  bool flag;
-};
-
-/// Represents the length modifier in a format string in scanf/printf.
-class LengthModifier {
-public:
-  enum Kind {
-    None,
-    AsChar,       // 'hh'
-    AsShort,      // 'h'
-    AsLong,       // 'l'
-    AsLongLong,   // 'll'
-    AsQuad,       // 'q' (BSD, deprecated, for 64-bit integer types)
-    AsIntMax,     // 'j'
-    AsSizeT,      // 'z'
-    AsPtrDiff,    // 't'
-    AsInt32,      // 'I32' (MSVCRT, like __int32)
-    AsInt3264,    // 'I'   (MSVCRT, like __int3264 from MIDL)
-    AsInt64,      // 'I64' (MSVCRT, like __int64)
-    AsLongDouble, // 'L'
-    AsAllocate,   // for '%as', GNU extension to C90 scanf
-    AsMAllocate,  // for '%ms', GNU extension to scanf
-    AsWide,       // 'w' (MSVCRT, like l but only for c, C, s, S, or Z
-    AsWideChar = AsLong // for '%ls', only makes sense for printf
-  };
-
-  LengthModifier()
-    : Position(nullptr), kind(None) {}
-  LengthModifier(const char *pos, Kind k)
-    : Position(pos), kind(k) {}
-
-  const char *getStart() const {
-    return Position;
-  }
-
-  unsigned getLength() const {
-    switch (kind) {
-      default:
-        return 1;
-      case AsLongLong:
-      case AsChar:
-        return 2;
-      case AsInt32:
-      case AsInt64:
-        return 3;
-      case None:
-        return 0;
-    }
-  }
-
-  Kind getKind() const { return kind; }
-  void setKind(Kind k) { kind = k; }
-
-  const char *toString() const;
-
-private:
-  const char *Position;
-  Kind kind;
-};
-
-class ConversionSpecifier {
-public:
-  enum Kind {
-    InvalidSpecifier = 0,
-    // C99 conversion specifiers.
-    cArg,
-    dArg,
-    DArg, // Apple extension
-    iArg,
-    IntArgBeg = dArg,
-    IntArgEnd = iArg,
-
-    oArg,
-    OArg, // Apple extension
-    uArg,
-    UArg, // Apple extension
-    xArg,
-    XArg,
-    UIntArgBeg = oArg,
-    UIntArgEnd = XArg,
-
-    fArg,
-    FArg,
-    eArg,
-    EArg,
-    gArg,
-    GArg,
-    aArg,
-    AArg,
-    DoubleArgBeg = fArg,
-    DoubleArgEnd = AArg,
-
-    sArg,
-    pArg,
-    nArg,
-    PercentArg,
-    CArg,
-    SArg,
-
-    // Apple extension: P specifies to os_log that the data being pointed to is
-    // to be copied by os_log. The precision indicates the number of bytes to
-    // copy.
-    PArg,
-
-    // ** Printf-specific **
-
-    ZArg, // MS extension
-
-    // Objective-C specific specifiers.
-    ObjCObjArg, // '@'
-    ObjCBeg = ObjCObjArg,
-    ObjCEnd = ObjCObjArg,
-
-    // FreeBSD kernel specific specifiers.
-    FreeBSDbArg,
-    FreeBSDDArg,
-    FreeBSDrArg,
-    FreeBSDyArg,
-
-    // GlibC specific specifiers.
-    PrintErrno, // 'm'
-
-    PrintfConvBeg = ObjCObjArg,
-    PrintfConvEnd = PrintErrno,
-
-    // ** Scanf-specific **
-    ScanListArg, // '['
-    ScanfConvBeg = ScanListArg,
-    ScanfConvEnd = ScanListArg
-  };
-
-  ConversionSpecifier(bool isPrintf = true)
-    : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
-      kind(InvalidSpecifier) {}
-
-  ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
-    : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
-
-  const char *getStart() const {
-    return Position;
-  }
-
-  StringRef getCharacters() const {
-    return StringRef(getStart(), getLength());
-  }
-
-  bool consumesDataArgument() const {
-    switch (kind) {
-      case PrintErrno:
-        assert(IsPrintf);
-        return false;
-      case PercentArg:
-        return false;
-      case InvalidSpecifier:
-        return false;
-      default:
-        return true;
-    }
-  }
-
-  Kind getKind() const { return kind; }
-  void setKind(Kind k) { kind = k; }
-  unsigned getLength() const {
-    return EndScanList ? EndScanList - Position : 1;
-  }
-  void setEndScanList(const char *pos) { EndScanList = pos; }
-
-  bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
-    kind == FreeBSDrArg || kind == FreeBSDyArg; }
-  bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
-  bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
-  bool isDoubleArg() const {
-    return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
-  }
-
-  const char *toString() const;
-
-  bool isPrintfKind() const { return IsPrintf; }
-
-  Optional<ConversionSpecifier> getStandardSpecifier() const;
-
-protected:
-  bool IsPrintf;
-  const char *Position;
-  const char *EndScanList;
-  Kind kind;
-};
-
-class ArgType {
-public:
-  enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
-              AnyCharTy, CStrTy, WCStrTy, WIntTy };
-
-  enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
-
-private:
-  const Kind K;
-  QualType T;
-  const char *Name = nullptr;
-  bool Ptr = false;
-
-  /// The TypeKind identifies certain well-known types like size_t and
-  /// ptrdiff_t.
-  enum class TypeKind { DontCare, SizeT, PtrdiffT };
-  TypeKind TK = TypeKind::DontCare;
-
-public:
-  ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
-  ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
-  ArgType(CanQualType T) : K(SpecificTy), T(T) {}
-
-  static ArgType Invalid() { return ArgType(InvalidTy); }
-  bool isValid() const { return K != InvalidTy; }
-
-  bool isSizeT() const { return TK == TypeKind::SizeT; }
-
-  bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
-
-  /// Create an ArgType which corresponds to the type pointer to A.
-  static ArgType PtrTo(const ArgType& A) {
-    assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
-    ArgType Res = A;
-    Res.Ptr = true;
-    return Res;
-  }
-
-  /// Create an ArgType which corresponds to the size_t/ssize_t type.
-  static ArgType makeSizeT(const ArgType &A) {
-    ArgType Res = A;
-    Res.TK = TypeKind::SizeT;
-    return Res;
-  }
-
-  /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
-  /// type.
-  static ArgType makePtrdiffT(const ArgType &A) {
-    ArgType Res = A;
-    Res.TK = TypeKind::PtrdiffT;
-    return Res;
-  }
-
-  MatchKind matchesType(ASTContext &C, QualType argTy) const;
-
-  QualType getRepresentativeType(ASTContext &C) const;
-
-  std::string getRepresentativeTypeName(ASTContext &C) const;
-};
-
-class OptionalAmount {
-public:
-  enum HowSpecified { NotSpecified, Constant, Arg, Invalid };
-
-  OptionalAmount(HowSpecified howSpecified,
-                 unsigned amount,
-                 const char *amountStart,
-                 unsigned amountLength,
-                 bool usesPositionalArg)
-  : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),
-  UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
-
-  OptionalAmount(bool valid = true)
-  : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
-  UsesPositionalArg(0), UsesDotPrefix(0) {}
-
-  bool isInvalid() const {
-    return hs == Invalid;
-  }
-
-  HowSpecified getHowSpecified() const { return hs; }
-  void setHowSpecified(HowSpecified h) { hs = h; }
-
-  bool hasDataArgument() const { return hs == Arg; }
-
-  unsigned getArgIndex() const {
-    assert(hasDataArgument());
-    return amt;
-  }
-
-  unsigned getConstantAmount() const {
-    assert(hs == Constant);
-    return amt;
-  }
-
-  const char *getStart() const {
-      // We include the . character if it is given.
-    return start - UsesDotPrefix;
-  }
-
-  unsigned getConstantLength() const {
-    assert(hs == Constant);
-    return length + UsesDotPrefix;
-  }
-
-  ArgType getArgType(ASTContext &Ctx) const;
-
-  void toString(raw_ostream &os) const;
-
-  bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
-  unsigned getPositionalArgIndex() const {
-    assert(hasDataArgument());
-    return amt + 1;
-  }
-
-  bool usesDotPrefix() const { return UsesDotPrefix; }
-  void setUsesDotPrefix() { UsesDotPrefix = true; }
-
-private:
-  const char *start;
-  unsigned length;
-  HowSpecified hs;
-  unsigned amt;
-  bool UsesPositionalArg : 1;
-  bool UsesDotPrefix;
-};
-
-
-class FormatSpecifier {
-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
-  bool UsesPositionalArg;
-  unsigned argIndex;
-public:
-  FormatSpecifier(bool isPrintf)
-    : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}
-
-  void setLengthModifier(LengthModifier lm) {
-    LM = lm;
-  }
-
-  void setUsesPositionalArg() { UsesPositionalArg = true; }
-
-  void setArgIndex(unsigned i) {
-    argIndex = i;
-  }
-
-  unsigned getArgIndex() const {
-    return argIndex;
-  }
-
-  unsigned getPositionalArgIndex() const {
-    return argIndex + 1;
-  }
-
-  const LengthModifier &getLengthModifier() const {
-    return LM;
-  }
-
-  const OptionalAmount &getFieldWidth() const {
-    return FieldWidth;
-  }
-
-  void setFieldWidth(const OptionalAmount &Amt) {
-    FieldWidth = Amt;
-  }
-
-  bool usesPositionalArg() const { return UsesPositionalArg; }
-
-  bool hasValidLengthModifier(const TargetInfo &Target) const;
-
-  bool hasStandardLengthModifier() const;
-
-  Optional<LengthModifier> getCorrectedLengthModifier() const;
-
-  bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
-
-  bool hasStandardLengthConversionCombination() const;
-
-  /// For a TypedefType QT, if it is a named integer type such as size_t,
-  /// assign the appropriate value to LM and return true.
-  static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
-};
-
-} // end analyze_format_string namespace
-
-//===----------------------------------------------------------------------===//
-/// Pieces specific to fprintf format strings.
-
-namespace analyze_printf {
-
-class PrintfConversionSpecifier :
-  public analyze_format_string::ConversionSpecifier  {
-public:
-  PrintfConversionSpecifier()
-    : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
-
-  PrintfConversionSpecifier(const char *pos, Kind k)
-    : ConversionSpecifier(true, pos, k) {}
-
-  bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
-  bool isDoubleArg() const { return kind >= DoubleArgBeg &&
-                                    kind <= DoubleArgEnd; }
-
-  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
-    return CS->isPrintfKind();
-  }
-};
-
-using analyze_format_string::ArgType;
-using analyze_format_string::LengthModifier;
-using analyze_format_string::OptionalAmount;
-using analyze_format_string::OptionalFlag;
-
-class PrintfSpecifier : public analyze_format_string::FormatSpecifier {
-  OptionalFlag HasThousandsGrouping; // ''', POSIX extension.
-  OptionalFlag IsLeftJustified; // '-'
-  OptionalFlag HasPlusPrefix; // '+'
-  OptionalFlag HasSpacePrefix; // ' '
-  OptionalFlag HasAlternativeForm; // '#'
-  OptionalFlag HasLeadingZeroes; // '0'
-  OptionalFlag HasObjCTechnicalTerm; // '[tt]'
-  OptionalFlag IsPrivate;            // '{private}'
-  OptionalFlag IsPublic;             // '{public}'
-  OptionalAmount Precision;
-public:
-  PrintfSpecifier()
-      : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
-        IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
-        HasAlternativeForm("#"), HasLeadingZeroes("0"),
-        HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public") {}
-
-  static PrintfSpecifier Parse(const char *beg, const char *end);
-
-    // Methods for incrementally constructing the PrintfSpecifier.
-  void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
-    CS = cs;
-  }
-  void setHasThousandsGrouping(const char *position) {
-    HasThousandsGrouping.setPosition(position);
-  }
-  void setIsLeftJustified(const char *position) {
-    IsLeftJustified.setPosition(position);
-  }
-  void setHasPlusPrefix(const char *position) {
-    HasPlusPrefix.setPosition(position);
-  }
-  void setHasSpacePrefix(const char *position) {
-    HasSpacePrefix.setPosition(position);
-  }
-  void setHasAlternativeForm(const char *position) {
-    HasAlternativeForm.setPosition(position);
-  }
-  void setHasLeadingZeros(const char *position) {
-    HasLeadingZeroes.setPosition(position);
-  }
-  void setHasObjCTechnicalTerm(const char *position) {
-    HasObjCTechnicalTerm.setPosition(position);
-  }
-  void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
-  void setIsPublic(const char *position) { IsPublic.setPosition(position); }
-  void setUsesPositionalArg() { UsesPositionalArg = true; }
-
-    // Methods for querying the format specifier.
-
-  const PrintfConversionSpecifier &getConversionSpecifier() const {
-    return cast<PrintfConversionSpecifier>(CS);
-  }
-
-  void setPrecision(const OptionalAmount &Amt) {
-    Precision = Amt;
-    Precision.setUsesDotPrefix();
-  }
-
-  const OptionalAmount &getPrecision() const {
-    return Precision;
-  }
-
-  bool consumesDataArgument() const {
-    return getConversionSpecifier().consumesDataArgument();
-  }
-
-  /// Returns the builtin type that a data argument
-  /// paired with this format specifier should have.  This method
-  /// will return null if the format specifier does not have
-  /// a matching data argument or the matching argument matches
-  /// more than one type.
-  ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
-
-  const OptionalFlag &hasThousandsGrouping() const {
-      return HasThousandsGrouping;
-  }
-  const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
-  const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
-  const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
-  const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
-  const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
-  const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
-  const OptionalFlag &isPrivate() const { return IsPrivate; }
-  const OptionalFlag &isPublic() const { return IsPublic; }
-  bool usesPositionalArg() const { return UsesPositionalArg; }
-
-  /// Changes the specifier and length according to a QualType, retaining any
-  /// flags or options. Returns true on success, or false when a conversion
-  /// was not successful.
-  bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,
-               bool IsObjCLiteral);
-
-  void toString(raw_ostream &os) const;
-
-  // Validation methods - to check if any element results in undefined behavior
-  bool hasValidPlusPrefix() const;
-  bool hasValidAlternativeForm() const;
-  bool hasValidLeadingZeros() const;
-  bool hasValidSpacePrefix() const;
-  bool hasValidLeftJustified() const;
-  bool hasValidThousandsGroupingPrefix() const;
-
-  bool hasValidPrecision() const;
-  bool hasValidFieldWidth() const;
-};
-}  // end analyze_printf namespace
-
-//===----------------------------------------------------------------------===//
-/// Pieces specific to fscanf format strings.
-
-namespace analyze_scanf {
-
-class ScanfConversionSpecifier :
-    public analyze_format_string::ConversionSpecifier  {
-public:
-  ScanfConversionSpecifier()
-    : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
-
-  ScanfConversionSpecifier(const char *pos, Kind k)
-    : ConversionSpecifier(false, pos, k) {}
-
-  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
-    return !CS->isPrintfKind();
-  }
-};
-
-using analyze_format_string::ArgType;
-using analyze_format_string::LengthModifier;
-using analyze_format_string::OptionalAmount;
-using analyze_format_string::OptionalFlag;
-
-class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
-  OptionalFlag SuppressAssignment; // '*'
-public:
-  ScanfSpecifier() :
-    FormatSpecifier(/* isPrintf = */ false),
-    SuppressAssignment("*") {}
-
-  void setSuppressAssignment(const char *position) {
-    SuppressAssignment.setPosition(position);
-  }
-
-  const OptionalFlag &getSuppressAssignment() const {
-    return SuppressAssignment;
-  }
-
-  void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
-    CS = cs;
-  }
-
-  const ScanfConversionSpecifier &getConversionSpecifier() const {
-    return cast<ScanfConversionSpecifier>(CS);
-  }
-
-  bool consumesDataArgument() const {
-    return CS.consumesDataArgument() && !SuppressAssignment;
-  }
-
-  ArgType getArgType(ASTContext &Ctx) const;
-
-  bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,
-               ASTContext &Ctx);
-
-  void toString(raw_ostream &os) const;
-
-  static ScanfSpecifier Parse(const char *beg, const char *end);
-};
-
-} // end analyze_scanf namespace
-
-//===----------------------------------------------------------------------===//
-// Parsing and processing of format strings (both fprintf and fscanf).
-
-namespace analyze_format_string {
-
-enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };
-
-class FormatStringHandler {
-public:
-  FormatStringHandler() {}
-  virtual ~FormatStringHandler();
-
-  virtual void HandleNullChar(const char *nullCharacter) {}
-
-  virtual void HandlePosition(const char *startPos, unsigned posLen) {}
-
-  virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
-                                     PositionContext p) {}
-
-  virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
-
-  virtual void HandleIncompleteSpecifier(const char *startSpecifier,
-                                         unsigned specifierLen) {}
-
-  virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
-                                           unsigned flagsLen) {}
-
-  virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
-                                             unsigned flagLen) {}
-
-  virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
-                                            const char *flagsEnd,
-                                            const char *conversionPosition) {}
-  // Printf-specific handlers.
-
-  virtual bool HandleInvalidPrintfConversionSpecifier(
-                                      const analyze_printf::PrintfSpecifier &FS,
-                                      const char *startSpecifier,
-                                      unsigned specifierLen) {
-    return true;
-  }
-
-  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
-                                     const char *startSpecifier,
-                                     unsigned specifierLen) {
-    return true;
-  }
-
-    // Scanf-specific handlers.
-
-  virtual bool HandleInvalidScanfConversionSpecifier(
-                                        const analyze_scanf::ScanfSpecifier &FS,
-                                        const char *startSpecifier,
-                                        unsigned specifierLen) {
-    return true;
-  }
-
-  virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
-                                    const char *startSpecifier,
-                                    unsigned specifierLen) {
-    return true;
-  }
-
-  virtual void HandleIncompleteScanList(const char *start, const char *end) {}
-};
-
-bool ParsePrintfString(FormatStringHandler &H,
-                       const char *beg, const char *end, const LangOptions &LO,
-                       const TargetInfo &Target, bool isFreeBSDKPrintf);
-
-bool ParseFormatStringHasSArg(const char *beg, const char *end,
-                              const LangOptions &LO, const TargetInfo &Target);
-
-bool ParseScanfString(FormatStringHandler &H,
-                      const char *beg, const char *end, const LangOptions &LO,
-                      const TargetInfo &Target);
-
-} // end analyze_format_string namespace
-} // end clang namespace
-#endif

Removed: cfe/trunk/include/clang/Analysis/Analyses/OSLog.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/OSLog.h?rev=345970&view=auto
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/OSLog.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/OSLog.h (removed)
@@ -1,155 +0,0 @@
-//= OSLog.h - Analysis of calls to os_log builtins --*- C++ -*-===============//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines APIs for determining the layout of the data buffer for
-// os_log() and os_trace().
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
-#define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Expr.h"
-
-namespace clang {
-namespace analyze_os_log {
-
-/// An OSLogBufferItem represents a single item in the data written by a call
-/// to os_log() or os_trace().
-class OSLogBufferItem {
-public:
-  enum Kind {
-    // The item is a scalar (int, float, raw pointer, etc.). No further copying
-    // is required. This is the only kind allowed by os_trace().
-    ScalarKind = 0,
-
-    // The item is a count, which describes the length of the following item to
-    // be copied. A count may only be followed by an item of kind StringKind,
-    // WideStringKind, or PointerKind.
-    CountKind,
-
-    // The item is a pointer to a C string. If preceded by a count 'n',
-    // os_log() will copy at most 'n' bytes from the pointer.
-    StringKind,
-
-    // The item is a pointer to a block of raw data. This item must be preceded
-    // by a count 'n'. os_log() will copy exactly 'n' bytes from the pointer.
-    PointerKind,
-
-    // The item is a pointer to an Objective-C object. os_log() may retain the
-    // object for later processing.
-    ObjCObjKind,
-
-    // The item is a pointer to wide-char string.
-    WideStringKind,
-
-    // The item is corresponding to the '%m' format specifier, no value is
-    // populated in the buffer and the runtime is loading the errno value.
-    ErrnoKind
-  };
-
-  enum {
-    // The item is marked "private" in the format string.
-    IsPrivate = 0x1,
-
-    // The item is marked "public" in the format string.
-    IsPublic = 0x2
-  };
-
-private:
-  Kind TheKind = ScalarKind;
-  const Expr *TheExpr = nullptr;
-  CharUnits ConstValue;
-  CharUnits Size; // size of the data, not including the header bytes
-  unsigned Flags = 0;
-
-public:
-  OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned flags)
-      : TheKind(kind), TheExpr(expr), Size(size), Flags(flags) {}
-
-  OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags)
-      : TheKind(CountKind), ConstValue(value),
-        Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {}
-
-  unsigned char getDescriptorByte() const {
-    unsigned char result = 0;
-    if (getIsPrivate())
-      result |= IsPrivate;
-    if (getIsPublic())
-      result |= IsPublic;
-    result |= ((unsigned)getKind()) << 4;
-    return result;
-  }
-
-  unsigned char getSizeByte() const { return size().getQuantity(); }
-
-  Kind getKind() const { return TheKind; }
-  bool getIsPrivate() const { return (Flags & IsPrivate) != 0; }
-  bool getIsPublic() const { return (Flags & IsPublic) != 0; }
-
-  const Expr *getExpr() const { return TheExpr; }
-  CharUnits getConstValue() const { return ConstValue; }
-  CharUnits size() const { return Size; }
-};
-
-class OSLogBufferLayout {
-public:
-  SmallVector<OSLogBufferItem, 4> Items;
-
-  enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 };
-
-  CharUnits size() const {
-    CharUnits result;
-    result += CharUnits::fromQuantity(2); // summary byte, num-args byte
-    for (auto &item : Items) {
-      // descriptor byte, size byte
-      result += item.size() + CharUnits::fromQuantity(2);
-    }
-    return result;
-  }
-
-  bool hasPrivateItems() const {
-    return llvm::any_of(
-        Items, [](const OSLogBufferItem &Item) { return Item.getIsPrivate(); });
-  }
-
-  bool hasPublicItems() const {
-    return llvm::any_of(
-        Items, [](const OSLogBufferItem &Item) { return Item.getIsPublic(); });
-  }
-
-  bool hasNonScalar() const {
-    return llvm::any_of(Items, [](const OSLogBufferItem &Item) {
-      return Item.getKind() != OSLogBufferItem::ScalarKind;
-    });
-  }
-
-  unsigned char getSummaryByte() const {
-    unsigned char result = 0;
-    if (hasPrivateItems())
-      result |= HasPrivateItems;
-    if (hasNonScalar())
-      result |= HasNonScalarItems;
-    return result;
-  }
-
-  unsigned char getNumArgsByte() const { return Items.size(); }
-};
-
-// Given a call 'E' to one of the builtins __builtin_os_log_format() or
-// __builtin_os_log_format_buffer_size(), compute the layout of the buffer that
-// the call will write into and store it in 'layout'. Returns 'false' if there
-// was some error encountered while computing the layout, and 'true' otherwise.
-bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const clang::CallExpr *E,
-                              OSLogBufferLayout &layout);
-
-} // namespace analyze_os_log
-} // namespace clang
-#endif

Modified: cfe/trunk/lib/AST/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CMakeLists.txt?rev=345971&r1=345970&r2=345971&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CMakeLists.txt (original)
+++ cfe/trunk/lib/AST/CMakeLists.txt Fri Nov  2 06:14:11 2018
@@ -39,6 +39,7 @@ add_clang_library(clangAST
   ExprObjC.cpp
   ExternalASTMerger.cpp
   ExternalASTSource.cpp
+  FormatString.cpp
   InheritViz.cpp
   ItaniumCXXABI.cpp
   ItaniumMangle.cpp
@@ -48,12 +49,15 @@ add_clang_library(clangAST
   NestedNameSpecifier.cpp
   NSAPI.cpp
   ODRHash.cpp
+  OSLog.cpp
   OpenMPClause.cpp
   ParentMap.cpp
+  PrintfFormatString.cpp
   QualTypeNames.cpp
   RawCommentList.cpp
   RecordLayout.cpp
   RecordLayoutBuilder.cpp
+  ScanfFormatString.cpp
   SelectorLocationsKind.cpp
   Stmt.cpp
   StmtCXX.cpp

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=345971&r1=345970&r2=345971&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Nov  2 06:14:11 2018
@@ -39,6 +39,7 @@
 #include "clang/AST/ASTLambda.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/OSLog.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/AST/TypeLoc.h"
@@ -8126,6 +8127,12 @@ bool IntExprEvaluator::VisitBuiltinCallE
     llvm_unreachable("unexpected EvalMode");
   }
 
+  case Builtin::BI__builtin_os_log_format_buffer_size: {
+    analyze_os_log::OSLogBufferLayout Layout;
+    analyze_os_log::computeOSLogBufferLayout(Info.Ctx, E, Layout);
+    return Success(Layout.size().getQuantity(), E);
+  }
+
   case Builtin::BI__builtin_bswap16:
   case Builtin::BI__builtin_bswap32:
   case Builtin::BI__builtin_bswap64: {

Added: cfe/trunk/lib/AST/FormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/FormatString.cpp?rev=345971&view=auto
==============================================================================
--- cfe/trunk/lib/AST/FormatString.cpp (added)
+++ cfe/trunk/lib/AST/FormatString.cpp Fri Nov  2 06:14:11 2018
@@ -0,0 +1,955 @@
+// FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Shared details for processing format strings of printf and scanf
+// (and friends).
+//
+//===----------------------------------------------------------------------===//
+
+#include "FormatStringParsing.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using clang::analyze_format_string::ArgType;
+using clang::analyze_format_string::FormatStringHandler;
+using clang::analyze_format_string::FormatSpecifier;
+using clang::analyze_format_string::LengthModifier;
+using clang::analyze_format_string::OptionalAmount;
+using clang::analyze_format_string::PositionContext;
+using clang::analyze_format_string::ConversionSpecifier;
+using namespace clang;
+
+// Key function to FormatStringHandler.
+FormatStringHandler::~FormatStringHandler() {}
+
+//===----------------------------------------------------------------------===//
+// Functions for parsing format strings components in both printf and
+// scanf format strings.
+//===----------------------------------------------------------------------===//
+
+OptionalAmount
+clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) {
+  const char *I = Beg;
+  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
+
+  unsigned accumulator = 0;
+  bool hasDigits = false;
+
+  for ( ; I != E; ++I) {
+    char c = *I;
+    if (c >= '0' && c <= '9') {
+      hasDigits = true;
+      accumulator = (accumulator * 10) + (c - '0');
+      continue;
+    }
+
+    if (hasDigits)
+      return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,
+          false);
+
+    break;
+  }
+
+  return OptionalAmount();
+}
+
+OptionalAmount
+clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,
+                                                     const char *E,
+                                                     unsigned &argIndex) {
+  if (*Beg == '*') {
+    ++Beg;
+    return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
+  }
+
+  return ParseAmount(Beg, E);
+}
+
+OptionalAmount
+clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,
+                                                  const char *Start,
+                                                  const char *&Beg,
+                                                  const char *E,
+                                                  PositionContext p) {
+  if (*Beg == '*') {
+    const char *I = Beg + 1;
+    const OptionalAmount &Amt = ParseAmount(I, E);
+
+    if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
+      H.HandleInvalidPosition(Beg, I - Beg, p);
+      return OptionalAmount(false);
+    }
+
+    if (I == E) {
+      // No more characters left?
+      H.HandleIncompleteSpecifier(Start, E - Start);
+      return OptionalAmount(false);
+    }
+
+    assert(Amt.getHowSpecified() == OptionalAmount::Constant);
+
+    if (*I == '$') {
+      // Handle positional arguments
+
+      // Special case: '*0$', since this is an easy mistake.
+      if (Amt.getConstantAmount() == 0) {
+        H.HandleZeroPosition(Beg, I - Beg + 1);
+        return OptionalAmount(false);
+      }
+
+      const char *Tmp = Beg;
+      Beg = ++I;
+
+      return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
+                            Tmp, 0, true);
+    }
+
+    H.HandleInvalidPosition(Beg, I - Beg, p);
+    return OptionalAmount(false);
+  }
+
+  return ParseAmount(Beg, E);
+}
+
+
+bool
+clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,
+                                              FormatSpecifier &CS,
+                                              const char *Start,
+                                              const char *&Beg, const char *E,
+                                              unsigned *argIndex) {
+  // FIXME: Support negative field widths.
+  if (argIndex) {
+    CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
+  }
+  else {
+    const OptionalAmount Amt =
+      ParsePositionAmount(H, Start, Beg, E,
+                          analyze_format_string::FieldWidthPos);
+
+    if (Amt.isInvalid())
+      return true;
+    CS.setFieldWidth(Amt);
+  }
+  return false;
+}
+
+bool
+clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
+                                               FormatSpecifier &FS,
+                                               const char *Start,
+                                               const char *&Beg,
+                                               const char *E) {
+  const char *I = Beg;
+
+  const OptionalAmount &Amt = ParseAmount(I, E);
+
+  if (I == E) {
+    // No more characters left?
+    H.HandleIncompleteSpecifier(Start, E - Start);
+    return true;
+  }
+
+  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);
+      return true;
+    }
+
+    FS.setArgIndex(Amt.getConstantAmount() - 1);
+    FS.setUsesPositionalArg();
+    // Update the caller's pointer if we decided to consume
+    // these characters.
+    Beg = I;
+    return false;
+  }
+
+  return false;
+}
+
+bool
+clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
+                                                  const char *&I,
+                                                  const char *E,
+                                                  const LangOptions &LO,
+                                                  bool IsScanf) {
+  LengthModifier::Kind lmKind = LengthModifier::None;
+  const char *lmPosition = I;
+  switch (*I) {
+    default:
+      return false;
+    case 'h':
+      ++I;
+      if (I != E && *I == 'h') {
+        ++I;
+        lmKind = LengthModifier::AsChar;
+      } else {
+        lmKind = LengthModifier::AsShort;
+      }
+      break;
+    case 'l':
+      ++I;
+      if (I != E && *I == 'l') {
+        ++I;
+        lmKind = LengthModifier::AsLongLong;
+      } else {
+        lmKind = LengthModifier::AsLong;
+      }
+      break;
+    case 'j': lmKind = LengthModifier::AsIntMax;     ++I; break;
+    case 'z': lmKind = LengthModifier::AsSizeT;      ++I; break;
+    case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;
+    case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
+    case 'q': lmKind = LengthModifier::AsQuad;       ++I; break;
+    case 'a':
+      if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
+        // 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;
+    case 'm':
+      if (IsScanf) {
+        lmKind = LengthModifier::AsMAllocate;
+        ++I;
+        break;
+      }
+      return false;
+    // printf: AsInt64, AsInt32, AsInt3264
+    // scanf:  AsInt64
+    case 'I':
+      if (I + 1 != E && I + 2 != E) {
+        if (I[1] == '6' && I[2] == '4') {
+          I += 3;
+          lmKind = LengthModifier::AsInt64;
+          break;
+        }
+        if (IsScanf)
+          return false;
+
+        if (I[1] == '3' && I[2] == '2') {
+          I += 3;
+          lmKind = LengthModifier::AsInt32;
+          break;
+        }
+      }
+      ++I;
+      lmKind = LengthModifier::AsInt3264;
+      break;
+    case 'w':
+      lmKind = LengthModifier::AsWide; ++I; break;
+  }
+  LengthModifier lm(lmPosition, lmKind);
+  FS.setLengthModifier(lm);
+  return true;
+}
+
+bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
+    const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {
+  if (SpecifierBegin + 1 >= FmtStrEnd)
+    return false;
+
+  const llvm::UTF8 *SB =
+      reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);
+  const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);
+  const char FirstByte = *SB;
+
+  // If the invalid specifier is a multibyte UTF-8 string, return the
+  // total length accordingly so that the conversion specifier can be
+  // properly updated to reflect a complete UTF-8 specifier.
+  unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);
+  if (NumBytes == 1)
+    return false;
+  if (SB + NumBytes > SE)
+    return false;
+
+  Len = NumBytes + 1;
+  return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Methods on ArgType.
+//===----------------------------------------------------------------------===//
+
+clang::analyze_format_string::ArgType::MatchKind
+ArgType::matchesType(ASTContext &C, QualType argTy) const {
+  if (Ptr) {
+    // It has to be a pointer.
+    const PointerType *PT = argTy->getAs<PointerType>();
+    if (!PT)
+      return NoMatch;
+
+    // We cannot write through a const qualified pointer.
+    if (PT->getPointeeType().isConstQualified())
+      return NoMatch;
+
+    argTy = PT->getPointeeType();
+  }
+
+  switch (K) {
+    case InvalidTy:
+      llvm_unreachable("ArgType must be valid");
+
+    case UnknownTy:
+      return Match;
+
+    case AnyCharTy: {
+      if (const EnumType *ETy = argTy->getAs<EnumType>()) {
+        // If the enum is incomplete we know nothing about the underlying type.
+        // Assume that it's 'int'.
+        if (!ETy->getDecl()->isComplete())
+          return NoMatch;
+        argTy = ETy->getDecl()->getIntegerType();
+      }
+
+      if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
+        switch (BT->getKind()) {
+          default:
+            break;
+          case BuiltinType::Char_S:
+          case BuiltinType::SChar:
+          case BuiltinType::UChar:
+          case BuiltinType::Char_U:
+            return Match;
+        }
+      return NoMatch;
+    }
+
+    case SpecificTy: {
+      if (const EnumType *ETy = argTy->getAs<EnumType>()) {
+        // If the enum is incomplete we know nothing about the underlying type.
+        // Assume that it's 'int'.
+        if (!ETy->getDecl()->isComplete())
+          argTy = C.IntTy;
+        else
+          argTy = ETy->getDecl()->getIntegerType();
+      }
+      argTy = C.getCanonicalType(argTy).getUnqualifiedType();
+
+      if (T == argTy)
+        return Match;
+      // Check for "compatible types".
+      if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
+        switch (BT->getKind()) {
+          default:
+            break;
+          case BuiltinType::Char_S:
+          case BuiltinType::SChar:
+          case BuiltinType::Char_U:
+          case BuiltinType::UChar:
+            return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match
+                                                                : NoMatch;
+          case BuiltinType::Short:
+            return T == C.UnsignedShortTy ? Match : NoMatch;
+          case BuiltinType::UShort:
+            return T == C.ShortTy ? Match : NoMatch;
+          case BuiltinType::Int:
+            return T == C.UnsignedIntTy ? Match : NoMatch;
+          case BuiltinType::UInt:
+            return T == C.IntTy ? Match : NoMatch;
+          case BuiltinType::Long:
+            return T == C.UnsignedLongTy ? Match : NoMatch;
+          case BuiltinType::ULong:
+            return T == C.LongTy ? Match : NoMatch;
+          case BuiltinType::LongLong:
+            return T == C.UnsignedLongLongTy ? Match : NoMatch;
+          case BuiltinType::ULongLong:
+            return T == C.LongLongTy ? Match : NoMatch;
+        }
+      return NoMatch;
+    }
+
+    case CStrTy: {
+      const PointerType *PT = argTy->getAs<PointerType>();
+      if (!PT)
+        return NoMatch;
+      QualType pointeeTy = PT->getPointeeType();
+      if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
+        switch (BT->getKind()) {
+          case BuiltinType::Void:
+          case BuiltinType::Char_U:
+          case BuiltinType::UChar:
+          case BuiltinType::Char_S:
+          case BuiltinType::SChar:
+            return Match;
+          default:
+            break;
+        }
+
+      return NoMatch;
+    }
+
+    case WCStrTy: {
+      const PointerType *PT = argTy->getAs<PointerType>();
+      if (!PT)
+        return NoMatch;
+      QualType pointeeTy =
+        C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
+      return pointeeTy == C.getWideCharType() ? Match : NoMatch;
+    }
+
+    case WIntTy: {
+      QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType();
+
+      if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)
+        return Match;
+
+      QualType PromoArg = argTy->isPromotableIntegerType()
+                              ? C.getPromotedIntegerType(argTy)
+                              : argTy;
+      PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
+
+      // If the promoted argument is the corresponding signed type of the
+      // wint_t type, then it should match.
+      if (PromoArg->hasSignedIntegerRepresentation() &&
+          C.getCorrespondingUnsignedType(PromoArg) == WInt)
+        return Match;
+
+      return WInt == PromoArg ? Match : NoMatch;
+    }
+
+    case CPointerTy:
+      if (argTy->isVoidPointerType()) {
+        return Match;
+      } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
+            argTy->isBlockPointerType() || argTy->isNullPtrType()) {
+        return NoMatchPedantic;
+      } else {
+        return NoMatch;
+      }
+
+    case ObjCPointerTy: {
+      if (argTy->getAs<ObjCObjectPointerType>() ||
+          argTy->getAs<BlockPointerType>())
+        return Match;
+
+      // Handle implicit toll-free bridging.
+      if (const PointerType *PT = argTy->getAs<PointerType>()) {
+        // Things such as CFTypeRef are really just opaque pointers
+        // to C structs representing CF types that can often be bridged
+        // to Objective-C objects.  Since the compiler doesn't know which
+        // structs can be toll-free bridged, we just accept them all.
+        QualType pointee = PT->getPointeeType();
+        if (pointee->getAsStructureType() || pointee->isVoidType())
+          return Match;
+      }
+      return NoMatch;
+    }
+  }
+
+  llvm_unreachable("Invalid ArgType Kind!");
+}
+
+QualType ArgType::getRepresentativeType(ASTContext &C) const {
+  QualType Res;
+  switch (K) {
+    case InvalidTy:
+      llvm_unreachable("No representative type for Invalid ArgType");
+    case UnknownTy:
+      llvm_unreachable("No representative type for Unknown ArgType");
+    case AnyCharTy:
+      Res = C.CharTy;
+      break;
+    case SpecificTy:
+      Res = T;
+      break;
+    case CStrTy:
+      Res = C.getPointerType(C.CharTy);
+      break;
+    case WCStrTy:
+      Res = C.getPointerType(C.getWideCharType());
+      break;
+    case ObjCPointerTy:
+      Res = C.ObjCBuiltinIdTy;
+      break;
+    case CPointerTy:
+      Res = C.VoidPtrTy;
+      break;
+    case WIntTy: {
+      Res = C.getWIntType();
+      break;
+    }
+  }
+
+  if (Ptr)
+    Res = C.getPointerType(Res);
+  return Res;
+}
+
+std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {
+  std::string S = getRepresentativeType(C).getAsString();
+
+  std::string Alias;
+  if (Name) {
+    // Use a specific name for this type, e.g. "size_t".
+    Alias = Name;
+    if (Ptr) {
+      // If ArgType is actually a pointer to T, append an asterisk.
+      Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";
+    }
+    // If Alias is the same as the underlying type, e.g. wchar_t, then drop it.
+    if (S == Alias)
+      Alias.clear();
+  }
+
+  if (!Alias.empty())
+    return std::string("'") + Alias + "' (aka '" + S + "')";
+  return std::string("'") + S + "'";
+}
+
+
+//===----------------------------------------------------------------------===//
+// Methods on OptionalAmount.
+//===----------------------------------------------------------------------===//
+
+ArgType
+analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {
+  return Ctx.IntTy;
+}
+
+//===----------------------------------------------------------------------===//
+// Methods on LengthModifier.
+//===----------------------------------------------------------------------===//
+
+const char *
+analyze_format_string::LengthModifier::toString() const {
+  switch (kind) {
+  case AsChar:
+    return "hh";
+  case AsShort:
+    return "h";
+  case AsLong: // or AsWideChar
+    return "l";
+  case AsLongLong:
+    return "ll";
+  case AsQuad:
+    return "q";
+  case AsIntMax:
+    return "j";
+  case AsSizeT:
+    return "z";
+  case AsPtrDiff:
+    return "t";
+  case AsInt32:
+    return "I32";
+  case AsInt3264:
+    return "I";
+  case AsInt64:
+    return "I64";
+  case AsLongDouble:
+    return "L";
+  case AsAllocate:
+    return "a";
+  case AsMAllocate:
+    return "m";
+  case AsWide:
+    return "w";
+  case None:
+    return "";
+  }
+  return nullptr;
+}
+
+//===----------------------------------------------------------------------===//
+// Methods on ConversionSpecifier.
+//===----------------------------------------------------------------------===//
+
+const char *ConversionSpecifier::toString() const {
+  switch (kind) {
+  case dArg: return "d";
+  case DArg: return "D";
+  case iArg: return "i";
+  case oArg: return "o";
+  case OArg: return "O";
+  case uArg: return "u";
+  case UArg: return "U";
+  case xArg: return "x";
+  case XArg: return "X";
+  case fArg: return "f";
+  case FArg: return "F";
+  case eArg: return "e";
+  case EArg: return "E";
+  case gArg: return "g";
+  case GArg: return "G";
+  case aArg: return "a";
+  case AArg: return "A";
+  case cArg: return "c";
+  case sArg: return "s";
+  case pArg: return "p";
+  case PArg:
+    return "P";
+  case nArg: return "n";
+  case PercentArg:  return "%";
+  case ScanListArg: return "[";
+  case InvalidSpecifier: return nullptr;
+
+  // POSIX unicode extensions.
+  case CArg: return "C";
+  case SArg: return "S";
+
+  // Objective-C specific specifiers.
+  case ObjCObjArg: return "@";
+
+  // FreeBSD kernel specific specifiers.
+  case FreeBSDbArg: return "b";
+  case FreeBSDDArg: return "D";
+  case FreeBSDrArg: return "r";
+  case FreeBSDyArg: return "y";
+
+  // GlibC specific specifiers.
+  case PrintErrno: return "m";
+
+  // MS specific specifiers.
+  case ZArg: return "Z";
+  }
+  return nullptr;
+}
+
+Optional<ConversionSpecifier>
+ConversionSpecifier::getStandardSpecifier() const {
+  ConversionSpecifier::Kind NewKind;
+
+  switch (getKind()) {
+  default:
+    return None;
+  case DArg:
+    NewKind = dArg;
+    break;
+  case UArg:
+    NewKind = uArg;
+    break;
+  case OArg:
+    NewKind = oArg;
+    break;
+  }
+
+  ConversionSpecifier FixedCS(*this);
+  FixedCS.setKind(NewKind);
+  return FixedCS;
+}
+
+//===----------------------------------------------------------------------===//
+// Methods on OptionalAmount.
+//===----------------------------------------------------------------------===//
+
+void OptionalAmount::toString(raw_ostream &os) const {
+  switch (hs) {
+  case Invalid:
+  case NotSpecified:
+    return;
+  case Arg:
+    if (UsesDotPrefix)
+        os << ".";
+    if (usesPositionalArg())
+      os << "*" << getPositionalArgIndex() << "$";
+    else
+      os << "*";
+    break;
+  case Constant:
+    if (UsesDotPrefix)
+        os << ".";
+    os << amt;
+    break;
+  }
+}
+
+bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
+  switch (LM.getKind()) {
+    case LengthModifier::None:
+      return true;
+
+    // Handle most integer flags
+    case LengthModifier::AsShort:
+      if (Target.getTriple().isOSMSVCRT()) {
+        switch (CS.getKind()) {
+          case ConversionSpecifier::cArg:
+          case ConversionSpecifier::CArg:
+          case ConversionSpecifier::sArg:
+          case ConversionSpecifier::SArg:
+          case ConversionSpecifier::ZArg:
+            return true;
+          default:
+            break;
+        }
+      }
+      LLVM_FALLTHROUGH;
+    case LengthModifier::AsChar:
+    case LengthModifier::AsLongLong:
+    case LengthModifier::AsQuad:
+    case LengthModifier::AsIntMax:
+    case LengthModifier::AsSizeT:
+    case LengthModifier::AsPtrDiff:
+      switch (CS.getKind()) {
+        case ConversionSpecifier::dArg:
+        case ConversionSpecifier::DArg:
+        case ConversionSpecifier::iArg:
+        case ConversionSpecifier::oArg:
+        case ConversionSpecifier::OArg:
+        case ConversionSpecifier::uArg:
+        case ConversionSpecifier::UArg:
+        case ConversionSpecifier::xArg:
+        case ConversionSpecifier::XArg:
+        case ConversionSpecifier::nArg:
+          return true;
+        case ConversionSpecifier::FreeBSDrArg:
+        case ConversionSpecifier::FreeBSDyArg:
+          return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS4();
+        default:
+          return false;
+      }
+
+    // Handle 'l' flag
+    case LengthModifier::AsLong: // or AsWideChar
+      switch (CS.getKind()) {
+        case ConversionSpecifier::dArg:
+        case ConversionSpecifier::DArg:
+        case ConversionSpecifier::iArg:
+        case ConversionSpecifier::oArg:
+        case ConversionSpecifier::OArg:
+        case ConversionSpecifier::uArg:
+        case ConversionSpecifier::UArg:
+        case ConversionSpecifier::xArg:
+        case ConversionSpecifier::XArg:
+        case ConversionSpecifier::aArg:
+        case ConversionSpecifier::AArg:
+        case ConversionSpecifier::fArg:
+        case ConversionSpecifier::FArg:
+        case ConversionSpecifier::eArg:
+        case ConversionSpecifier::EArg:
+        case ConversionSpecifier::gArg:
+        case ConversionSpecifier::GArg:
+        case ConversionSpecifier::nArg:
+        case ConversionSpecifier::cArg:
+        case ConversionSpecifier::sArg:
+        case ConversionSpecifier::ScanListArg:
+        case ConversionSpecifier::ZArg:
+          return true;
+        case ConversionSpecifier::FreeBSDrArg:
+        case ConversionSpecifier::FreeBSDyArg:
+          return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS4();
+        default:
+          return false;
+      }
+
+    case LengthModifier::AsLongDouble:
+      switch (CS.getKind()) {
+        case ConversionSpecifier::aArg:
+        case ConversionSpecifier::AArg:
+        case ConversionSpecifier::fArg:
+        case ConversionSpecifier::FArg:
+        case ConversionSpecifier::eArg:
+        case ConversionSpecifier::EArg:
+        case ConversionSpecifier::gArg:
+        case ConversionSpecifier::GArg:
+          return true;
+        // GNU libc extension.
+        case ConversionSpecifier::dArg:
+        case ConversionSpecifier::iArg:
+        case ConversionSpecifier::oArg:
+        case ConversionSpecifier::uArg:
+        case ConversionSpecifier::xArg:
+        case ConversionSpecifier::XArg:
+          return !Target.getTriple().isOSDarwin() &&
+                 !Target.getTriple().isOSWindows();
+        default:
+          return false;
+      }
+
+    case LengthModifier::AsAllocate:
+      switch (CS.getKind()) {
+        case ConversionSpecifier::sArg:
+        case ConversionSpecifier::SArg:
+        case ConversionSpecifier::ScanListArg:
+          return true;
+        default:
+          return false;
+      }
+
+    case LengthModifier::AsMAllocate:
+      switch (CS.getKind()) {
+        case ConversionSpecifier::cArg:
+        case ConversionSpecifier::CArg:
+        case ConversionSpecifier::sArg:
+        case ConversionSpecifier::SArg:
+        case ConversionSpecifier::ScanListArg:
+          return true;
+        default:
+          return false;
+      }
+    case LengthModifier::AsInt32:
+    case LengthModifier::AsInt3264:
+    case LengthModifier::AsInt64:
+      switch (CS.getKind()) {
+        case ConversionSpecifier::dArg:
+        case ConversionSpecifier::iArg:
+        case ConversionSpecifier::oArg:
+        case ConversionSpecifier::uArg:
+        case ConversionSpecifier::xArg:
+        case ConversionSpecifier::XArg:
+          return Target.getTriple().isOSMSVCRT();
+        default:
+          return false;
+      }
+    case LengthModifier::AsWide:
+      switch (CS.getKind()) {
+        case ConversionSpecifier::cArg:
+        case ConversionSpecifier::CArg:
+        case ConversionSpecifier::sArg:
+        case ConversionSpecifier::SArg:
+        case ConversionSpecifier::ZArg:
+          return Target.getTriple().isOSMSVCRT();
+        default:
+          return false;
+      }
+  }
+  llvm_unreachable("Invalid LengthModifier Kind!");
+}
+
+bool FormatSpecifier::hasStandardLengthModifier() const {
+  switch (LM.getKind()) {
+    case LengthModifier::None:
+    case LengthModifier::AsChar:
+    case LengthModifier::AsShort:
+    case LengthModifier::AsLong:
+    case LengthModifier::AsLongLong:
+    case LengthModifier::AsIntMax:
+    case LengthModifier::AsSizeT:
+    case LengthModifier::AsPtrDiff:
+    case LengthModifier::AsLongDouble:
+      return true;
+    case LengthModifier::AsAllocate:
+    case LengthModifier::AsMAllocate:
+    case LengthModifier::AsQuad:
+    case LengthModifier::AsInt32:
+    case LengthModifier::AsInt3264:
+    case LengthModifier::AsInt64:
+    case LengthModifier::AsWide:
+      return false;
+  }
+  llvm_unreachable("Invalid LengthModifier Kind!");
+}
+
+bool FormatSpecifier::hasStandardConversionSpecifier(
+    const LangOptions &LangOpt) const {
+  switch (CS.getKind()) {
+    case ConversionSpecifier::cArg:
+    case ConversionSpecifier::dArg:
+    case ConversionSpecifier::iArg:
+    case ConversionSpecifier::oArg:
+    case ConversionSpecifier::uArg:
+    case ConversionSpecifier::xArg:
+    case ConversionSpecifier::XArg:
+    case ConversionSpecifier::fArg:
+    case ConversionSpecifier::FArg:
+    case ConversionSpecifier::eArg:
+    case ConversionSpecifier::EArg:
+    case ConversionSpecifier::gArg:
+    case ConversionSpecifier::GArg:
+    case ConversionSpecifier::aArg:
+    case ConversionSpecifier::AArg:
+    case ConversionSpecifier::sArg:
+    case ConversionSpecifier::pArg:
+    case ConversionSpecifier::nArg:
+    case ConversionSpecifier::ObjCObjArg:
+    case ConversionSpecifier::ScanListArg:
+    case ConversionSpecifier::PercentArg:
+    case ConversionSpecifier::PArg:
+      return true;
+    case ConversionSpecifier::CArg:
+    case ConversionSpecifier::SArg:
+      return LangOpt.ObjC;
+    case ConversionSpecifier::InvalidSpecifier:
+    case ConversionSpecifier::FreeBSDbArg:
+    case ConversionSpecifier::FreeBSDDArg:
+    case ConversionSpecifier::FreeBSDrArg:
+    case ConversionSpecifier::FreeBSDyArg:
+    case ConversionSpecifier::PrintErrno:
+    case ConversionSpecifier::DArg:
+    case ConversionSpecifier::OArg:
+    case ConversionSpecifier::UArg:
+    case ConversionSpecifier::ZArg:
+      return false;
+  }
+  llvm_unreachable("Invalid ConversionSpecifier Kind!");
+}
+
+bool FormatSpecifier::hasStandardLengthConversionCombination() const {
+  if (LM.getKind() == LengthModifier::AsLongDouble) {
+    switch(CS.getKind()) {
+        case ConversionSpecifier::dArg:
+        case ConversionSpecifier::iArg:
+        case ConversionSpecifier::oArg:
+        case ConversionSpecifier::uArg:
+        case ConversionSpecifier::xArg:
+        case ConversionSpecifier::XArg:
+          return false;
+        default:
+          return true;
+    }
+  }
+  return true;
+}
+
+Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier() const {
+  if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
+    if (LM.getKind() == LengthModifier::AsLongDouble ||
+        LM.getKind() == LengthModifier::AsQuad) {
+      LengthModifier FixedLM(LM);
+      FixedLM.setKind(LengthModifier::AsLongLong);
+      return FixedLM;
+    }
+  }
+
+  return None;
+}
+
+bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
+                                                LengthModifier &LM) {
+  assert(isa<TypedefType>(QT) && "Expected a TypedefType");
+  const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();
+
+  for (;;) {
+    const IdentifierInfo *Identifier = Typedef->getIdentifier();
+    if (Identifier->getName() == "size_t") {
+      LM.setKind(LengthModifier::AsSizeT);
+      return true;
+    } else if (Identifier->getName() == "ssize_t") {
+      // Not C99, but common in Unix.
+      LM.setKind(LengthModifier::AsSizeT);
+      return true;
+    } else if (Identifier->getName() == "intmax_t") {
+      LM.setKind(LengthModifier::AsIntMax);
+      return true;
+    } else if (Identifier->getName() == "uintmax_t") {
+      LM.setKind(LengthModifier::AsIntMax);
+      return true;
+    } else if (Identifier->getName() == "ptrdiff_t") {
+      LM.setKind(LengthModifier::AsPtrDiff);
+      return true;
+    }
+
+    QualType T = Typedef->getUnderlyingType();
+    if (!isa<TypedefType>(T))
+      break;
+
+    Typedef = cast<TypedefType>(T)->getDecl();
+  }
+  return false;
+}

Added: cfe/trunk/lib/AST/FormatStringParsing.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/FormatStringParsing.h?rev=345971&view=auto
==============================================================================
--- cfe/trunk/lib/AST/FormatStringParsing.h (added)
+++ cfe/trunk/lib/AST/FormatStringParsing.h Fri Nov  2 06:14:11 2018
@@ -0,0 +1,79 @@
+#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
+#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/FormatString.h"
+
+namespace clang {
+
+class LangOptions;
+
+template <typename T>
+class UpdateOnReturn {
+  T &ValueToUpdate;
+  const T &ValueToCopy;
+public:
+  UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
+    : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
+
+  ~UpdateOnReturn() {
+    ValueToUpdate = ValueToCopy;
+  }
+};
+
+namespace analyze_format_string {
+
+OptionalAmount ParseAmount(const char *&Beg, const char *E);
+OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
+                                      unsigned &argIndex);
+
+OptionalAmount ParsePositionAmount(FormatStringHandler &H,
+                                   const char *Start, const char *&Beg,
+                                   const char *E, PositionContext p);
+
+bool ParseFieldWidth(FormatStringHandler &H,
+                     FormatSpecifier &CS,
+                     const char *Start, const char *&Beg, const char *E,
+                     unsigned *argIndex);
+
+bool ParseArgPosition(FormatStringHandler &H,
+                      FormatSpecifier &CS, const char *Start,
+                      const char *&Beg, const char *E);
+
+/// Returns true if a LengthModifier was parsed and installed in the
+/// FormatSpecifier& argument, and false otherwise.
+bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E,
+                         const LangOptions &LO, bool IsScanf = false);
+
+/// Returns true if the invalid specifier in \p SpecifierBegin is a UTF-8
+/// string; check that it won't go further than \p FmtStrEnd and write
+/// up the total size in \p Len.
+bool ParseUTF8InvalidSpecifier(const char *SpecifierBegin,
+                               const char *FmtStrEnd, unsigned &Len);
+
+template <typename T> class SpecifierResult {
+  T FS;
+  const char *Start;
+  bool Stop;
+public:
+  SpecifierResult(bool stop = false)
+  : Start(nullptr), Stop(stop) {}
+  SpecifierResult(const char *start,
+                  const T &fs)
+  : FS(fs), Start(start), Stop(false) {}
+
+  const char *getStart() const { return Start; }
+  bool shouldStop() const { return Stop; }
+  bool hasValue() const { return Start != nullptr; }
+  const T &getValue() const {
+    assert(hasValue());
+    return FS;
+  }
+  const T &getValue() { return FS; }
+};
+
+} // end analyze_format_string namespace
+} // end clang namespace
+
+#endif

Added: cfe/trunk/lib/AST/OSLog.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/OSLog.cpp?rev=345971&view=auto
==============================================================================
--- cfe/trunk/lib/AST/OSLog.cpp (added)
+++ cfe/trunk/lib/AST/OSLog.cpp Fri Nov  2 06:14:11 2018
@@ -0,0 +1,203 @@
+// TODO: header template
+
+#include "clang/AST/OSLog.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/FormatString.h"
+#include "clang/Basic/Builtins.h"
+#include "llvm/ADT/SmallBitVector.h"
+
+using namespace clang;
+
+using clang::analyze_os_log::OSLogBufferItem;
+using clang::analyze_os_log::OSLogBufferLayout;
+
+namespace {
+class OSLogFormatStringHandler
+    : public analyze_format_string::FormatStringHandler {
+private:
+  struct ArgData {
+    const Expr *E = nullptr;
+    Optional<OSLogBufferItem::Kind> Kind;
+    Optional<unsigned> Size;
+    Optional<const Expr *> Count;
+    Optional<const Expr *> Precision;
+    Optional<const Expr *> FieldWidth;
+    unsigned char Flags = 0;
+  };
+  SmallVector<ArgData, 4> ArgsData;
+  ArrayRef<const Expr *> Args;
+
+  OSLogBufferItem::Kind
+  getKind(analyze_format_string::ConversionSpecifier::Kind K) {
+    switch (K) {
+    case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
+      return OSLogBufferItem::StringKind;
+    case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"
+      return OSLogBufferItem::WideStringKind;
+    case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
+      return OSLogBufferItem::PointerKind;
+    case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg: // "%@"
+      return OSLogBufferItem::ObjCObjKind;
+    case clang::analyze_format_string::ConversionSpecifier::PrintErrno: // "%m"
+      return OSLogBufferItem::ErrnoKind;
+    default:
+      return OSLogBufferItem::ScalarKind;
+    }
+    }
+  }
+
+public:
+  OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
+    ArgsData.reserve(Args.size());
+  }
+
+  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
+                                     const char *StartSpecifier,
+                                     unsigned SpecifierLen) {
+    if (!FS.consumesDataArgument() &&
+        FS.getConversionSpecifier().getKind() !=
+            clang::analyze_format_string::ConversionSpecifier::PrintErrno)
+      return true;
+
+    ArgsData.emplace_back();
+    unsigned ArgIndex = FS.getArgIndex();
+    if (ArgIndex < Args.size())
+      ArgsData.back().E = Args[ArgIndex];
+
+    // First get the Kind
+    ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
+    if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
+        !ArgsData.back().E) {
+      // missing argument
+      ArgsData.pop_back();
+      return false;
+    }
+
+    switch (FS.getConversionSpecifier().getKind()) {
+    case clang::analyze_format_string::ConversionSpecifier::sArg:   // "%s"
+    case clang::analyze_format_string::ConversionSpecifier::SArg: { // "%S"
+      auto &precision = FS.getPrecision();
+      switch (precision.getHowSpecified()) {
+      case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s"
+        break;
+      case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s"
+        ArgsData.back().Size = precision.getConstantAmount();
+        break;
+      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
+        ArgsData.back().Count = Args[precision.getArgIndex()];
+        break;
+      case clang::analyze_format_string::OptionalAmount::Invalid:
+        return false;
+      }
+      break;
+    }
+    case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
+      auto &precision = FS.getPrecision();
+      switch (precision.getHowSpecified()) {
+      case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P"
+        return false; // length must be supplied with pointer format specifier
+      case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P"
+        ArgsData.back().Size = precision.getConstantAmount();
+        break;
+      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
+        ArgsData.back().Count = Args[precision.getArgIndex()];
+        break;
+      case clang::analyze_format_string::OptionalAmount::Invalid:
+        return false;
+      }
+      break;
+    }
+    default:
+      if (FS.getPrecision().hasDataArgument()) {
+        ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
+      }
+      break;
+    }
+    if (FS.getFieldWidth().hasDataArgument()) {
+      ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
+    }
+
+    if (FS.isPrivate()) {
+      ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
+    }
+    if (FS.isPublic()) {
+      ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
+    }
+    return true;
+  }
+
+  void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
+    Layout.Items.clear();
+    for (auto &Data : ArgsData) {
+      if (Data.FieldWidth) {
+        CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
+        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,
+                                  Size, 0);
+      }
+      if (Data.Precision) {
+        CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());
+        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,
+                                  Size, 0);
+      }
+      if (Data.Count) {
+        // "%.*P" has an extra "count" that we insert before the argument.
+        CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
+        Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,
+                                  0);
+      }
+      if (Data.Size)
+        Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),
+                                  Data.Flags);
+      if (Data.Kind) {
+        CharUnits Size;
+        if (*Data.Kind == OSLogBufferItem::ErrnoKind)
+          Size = CharUnits::Zero();
+        else
+          Size = Ctx.getTypeSizeInChars(Data.E->getType());
+        Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
+      } else {
+        auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
+        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size,
+                                  Data.Flags);
+      }
+    }
+  }
+};
+} // end anonymous namespace
+
+bool clang::analyze_os_log::computeOSLogBufferLayout(
+    ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
+  ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());
+
+  const Expr *StringArg;
+  ArrayRef<const Expr *> VarArgs;
+  switch (E->getBuiltinCallee()) {
+  case Builtin::BI__builtin_os_log_format_buffer_size:
+    assert(E->getNumArgs() >= 1 &&
+           "__builtin_os_log_format_buffer_size takes at least 1 argument");
+    StringArg = E->getArg(0);
+    VarArgs = Args.slice(1);
+    break;
+  case Builtin::BI__builtin_os_log_format:
+    assert(E->getNumArgs() >= 2 &&
+           "__builtin_os_log_format takes at least 2 arguments");
+    StringArg = E->getArg(1);
+    VarArgs = Args.slice(2);
+    break;
+  default:
+    llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");
+  }
+
+  const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());
+  assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
+  StringRef Data = Lit->getString();
+  OSLogFormatStringHandler H(VarArgs);
+  ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
+                    Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
+
+  H.computeLayout(Ctx, Layout);
+  return true;
+}

Added: cfe/trunk/lib/AST/PrintfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/PrintfFormatString.cpp?rev=345971&view=auto
==============================================================================
--- cfe/trunk/lib/AST/PrintfFormatString.cpp (added)
+++ cfe/trunk/lib/AST/PrintfFormatString.cpp Fri Nov  2 06:14:11 2018
@@ -0,0 +1,1029 @@
+//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handling of format string in printf and friends.  The structure of format
+// strings for fprintf() are described in C99 7.19.6.1.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/FormatString.h"
+#include "clang/AST/OSLog.h"
+#include "FormatStringParsing.h"
+#include "clang/Basic/TargetInfo.h"
+
+using clang::analyze_format_string::ArgType;
+using clang::analyze_format_string::FormatStringHandler;
+using clang::analyze_format_string::LengthModifier;
+using clang::analyze_format_string::OptionalAmount;
+using clang::analyze_format_string::ConversionSpecifier;
+using clang::analyze_printf::PrintfSpecifier;
+
+using namespace clang;
+
+typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
+        PrintfSpecifierResult;
+
+//===----------------------------------------------------------------------===//
+// Methods for parsing format strings.
+//===----------------------------------------------------------------------===//
+
+using analyze_format_string::ParseNonPositionAmount;
+
+static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
+                           const char *Start, const char *&Beg, const char *E,
+                           unsigned *argIndex) {
+  if (argIndex) {
+    FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
+  } else {
+    const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
+                                           analyze_format_string::PrecisionPos);
+    if (Amt.isInvalid())
+      return true;
+    FS.setPrecision(Amt);
+  }
+  return false;
+}
+
+static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
+                           const char *FlagBeg, const char *E, bool Warn) {
+   StringRef Flag(FlagBeg, E - FlagBeg);
+   // Currently there is only one flag.
+   if (Flag == "tt") {
+     FS.setHasObjCTechnicalTerm(FlagBeg);
+     return false;
+   }
+   // Handle either the case of no flag or an invalid flag.
+   if (Warn) {
+     if (Flag == "")
+       H.HandleEmptyObjCModifierFlag(FlagBeg, E  - FlagBeg);
+     else
+       H.HandleInvalidObjCModifierFlag(FlagBeg, E  - FlagBeg);
+   }
+   return true;
+}
+
+static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
+                                                  const char *&Beg,
+                                                  const char *E,
+                                                  unsigned &argIndex,
+                                                  const LangOptions &LO,
+                                                  const TargetInfo &Target,
+                                                  bool Warn,
+                                                  bool isFreeBSDKPrintf) {
+
+  using namespace clang::analyze_format_string;
+  using namespace clang::analyze_printf;
+
+  const char *I = Beg;
+  const char *Start = nullptr;
+  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
+
+  // Look for a '%' character that indicates the start of a format specifier.
+  for ( ; I != E ; ++I) {
+    char c = *I;
+    if (c == '\0') {
+      // Detect spurious null characters, which are likely errors.
+      H.HandleNullChar(I);
+      return true;
+    }
+    if (c == '%') {
+      Start = I++;  // Record the start of the format specifier.
+      break;
+    }
+  }
+
+  // No format specifier found?
+  if (!Start)
+    return false;
+
+  if (I == E) {
+    // No more characters left?
+    if (Warn)
+      H.HandleIncompleteSpecifier(Start, E - Start);
+    return true;
+  }
+
+  PrintfSpecifier FS;
+  if (ParseArgPosition(H, FS, Start, I, E))
+    return true;
+
+  if (I == E) {
+    // No more characters left?
+    if (Warn)
+      H.HandleIncompleteSpecifier(Start, E - Start);
+    return true;
+  }
+
+  if (*I == '{') {
+    ++I;
+    unsigned char PrivacyFlags = 0;
+    StringRef MatchedStr;
+
+    do {
+      StringRef Str(I, E - I);
+      std::string Match = "^[\t\n\v\f\r ]*(private|public)[\t\n\v\f\r ]*(,|})";
+      llvm::Regex R(Match);
+      SmallVector<StringRef, 2> Matches;
+
+      if (R.match(Str, &Matches)) {
+        MatchedStr = Matches[1];
+        I += Matches[0].size();
+
+        // Set the privacy flag if the privacy annotation in the
+        // comma-delimited segment is at least as strict as the privacy
+        // annotations in previous comma-delimited segments.
+        if (MatchedStr.equals("private"))
+          PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;
+        else if (PrivacyFlags == 0 && MatchedStr.equals("public"))
+          PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
+      } else {
+        size_t CommaOrBracePos =
+            Str.find_if([](char c) { return c == ',' || c == '}'; });
+
+        if (CommaOrBracePos == StringRef::npos) {
+          // Neither a comma nor the closing brace was found.
+          if (Warn)
+            H.HandleIncompleteSpecifier(Start, E - Start);
+          return true;
+        }
+
+        I += CommaOrBracePos + 1;
+      }
+      // Continue until the closing brace is found.
+    } while (*(I - 1) == ',');
+
+    // Set the privacy flag.
+    switch (PrivacyFlags) {
+    case 0:
+      break;
+    case clang::analyze_os_log::OSLogBufferItem::IsPrivate:
+      FS.setIsPrivate(MatchedStr.data());
+      break;
+    case clang::analyze_os_log::OSLogBufferItem::IsPublic:
+      FS.setIsPublic(MatchedStr.data());
+      break;
+    default:
+      llvm_unreachable("Unexpected privacy flag value");
+    }
+  }
+
+  // Look for flags (if any).
+  bool hasMore = true;
+  for ( ; I != E; ++I) {
+    switch (*I) {
+      default: hasMore = false; break;
+      case '\'':
+        // FIXME: POSIX specific.  Always accept?
+        FS.setHasThousandsGrouping(I);
+        break;
+      case '-': FS.setIsLeftJustified(I); break;
+      case '+': FS.setHasPlusPrefix(I); break;
+      case ' ': FS.setHasSpacePrefix(I); break;
+      case '#': FS.setHasAlternativeForm(I); break;
+      case '0': FS.setHasLeadingZeros(I); break;
+    }
+    if (!hasMore)
+      break;
+  }
+
+  if (I == E) {
+    // No more characters left?
+    if (Warn)
+      H.HandleIncompleteSpecifier(Start, E - Start);
+    return true;
+  }
+
+  // Look for the field width (if any).
+  if (ParseFieldWidth(H, FS, Start, I, E,
+                      FS.usesPositionalArg() ? nullptr : &argIndex))
+    return true;
+
+  if (I == E) {
+    // No more characters left?
+    if (Warn)
+      H.HandleIncompleteSpecifier(Start, E - Start);
+    return true;
+  }
+
+  // Look for the precision (if any).
+  if (*I == '.') {
+    ++I;
+    if (I == E) {
+      if (Warn)
+        H.HandleIncompleteSpecifier(Start, E - Start);
+      return true;
+    }
+
+    if (ParsePrecision(H, FS, Start, I, E,
+                       FS.usesPositionalArg() ? nullptr : &argIndex))
+      return true;
+
+    if (I == E) {
+      // No more characters left?
+      if (Warn)
+        H.HandleIncompleteSpecifier(Start, E - Start);
+      return true;
+    }
+  }
+
+  // Look for the length modifier.
+  if (ParseLengthModifier(FS, I, E, LO) && I == E) {
+    // No more characters left?
+    if (Warn)
+      H.HandleIncompleteSpecifier(Start, E - Start);
+    return true;
+  }
+
+  // Look for the Objective-C modifier flags, if any.
+  // We parse these here, even if they don't apply to
+  // the conversion specifier, and then emit an error
+  // later if the conversion specifier isn't '@'.  This
+  // enables better recovery, and we don't know if
+  // these flags are applicable until later.
+  const char *ObjCModifierFlagsStart = nullptr,
+             *ObjCModifierFlagsEnd = nullptr;
+  if (*I == '[') {
+    ObjCModifierFlagsStart = I;
+    ++I;
+    auto flagStart = I;
+    for (;; ++I) {
+      ObjCModifierFlagsEnd = I;
+      if (I == E) {
+        if (Warn)
+          H.HandleIncompleteSpecifier(Start, E - Start);
+        return true;
+      }
+      // Did we find the closing ']'?
+      if (*I == ']') {
+        if (ParseObjCFlags(H, FS, flagStart, I, Warn))
+          return true;
+        ++I;
+        break;
+      }
+      // There are no separators defined yet for multiple
+      // Objective-C modifier flags.  When those are
+      // defined, this is the place to check.
+    }
+  }
+
+  if (*I == '\0') {
+    // Detect spurious null characters, which are likely errors.
+    H.HandleNullChar(I);
+    return true;
+  }
+
+  // Finally, look for the conversion specifier.
+  const char *conversionPosition = I++;
+  ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
+  switch (*conversionPosition) {
+    default:
+      break;
+    // C99: 7.19.6.1 (section 8).
+    case '%': k = ConversionSpecifier::PercentArg;   break;
+    case 'A': k = ConversionSpecifier::AArg; break;
+    case 'E': k = ConversionSpecifier::EArg; break;
+    case 'F': k = ConversionSpecifier::FArg; break;
+    case 'G': k = ConversionSpecifier::GArg; break;
+    case 'X': k = ConversionSpecifier::XArg; break;
+    case 'a': k = ConversionSpecifier::aArg; break;
+    case 'c': k = ConversionSpecifier::cArg; break;
+    case 'd': k = ConversionSpecifier::dArg; break;
+    case 'e': k = ConversionSpecifier::eArg; break;
+    case 'f': k = ConversionSpecifier::fArg; break;
+    case 'g': k = ConversionSpecifier::gArg; break;
+    case 'i': k = ConversionSpecifier::iArg; break;
+    case 'n': k = ConversionSpecifier::nArg; break;
+    case 'o': k = ConversionSpecifier::oArg; break;
+    case 'p': k = ConversionSpecifier::pArg; break;
+    case 's': k = ConversionSpecifier::sArg; break;
+    case 'u': k = ConversionSpecifier::uArg; break;
+    case 'x': k = ConversionSpecifier::xArg; break;
+    // POSIX specific.
+    case 'C': k = ConversionSpecifier::CArg; break;
+    case 'S': k = ConversionSpecifier::SArg; break;
+    // Apple extension for os_log
+    case 'P':
+      k = ConversionSpecifier::PArg;
+      break;
+    // Objective-C.
+    case '@': k = ConversionSpecifier::ObjCObjArg; break;
+    // Glibc specific.
+    case 'm': k = ConversionSpecifier::PrintErrno; break;
+    // FreeBSD kernel specific.
+    case 'b':
+      if (isFreeBSDKPrintf)
+        k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
+      break;
+    case 'r':
+      if (isFreeBSDKPrintf)
+        k = ConversionSpecifier::FreeBSDrArg; // int
+      break;
+    case 'y':
+      if (isFreeBSDKPrintf)
+        k = ConversionSpecifier::FreeBSDyArg; // int
+      break;
+    // Apple-specific.
+    case 'D':
+      if (isFreeBSDKPrintf)
+        k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
+      else if (Target.getTriple().isOSDarwin())
+        k = ConversionSpecifier::DArg;
+      break;
+    case 'O':
+      if (Target.getTriple().isOSDarwin())
+        k = ConversionSpecifier::OArg;
+      break;
+    case 'U':
+      if (Target.getTriple().isOSDarwin())
+        k = ConversionSpecifier::UArg;
+      break;
+    // MS specific.
+    case 'Z':
+      if (Target.getTriple().isOSMSVCRT())
+        k = ConversionSpecifier::ZArg;
+  }
+
+  // Check to see if we used the Objective-C modifier flags with
+  // a conversion specifier other than '@'.
+  if (k != ConversionSpecifier::ObjCObjArg &&
+      k != ConversionSpecifier::InvalidSpecifier &&
+      ObjCModifierFlagsStart) {
+    H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,
+                                           ObjCModifierFlagsEnd + 1,
+                                           conversionPosition);
+    return true;
+  }
+
+  PrintfConversionSpecifier CS(conversionPosition, k);
+  FS.setConversionSpecifier(CS);
+  if (CS.consumesDataArgument() && !FS.usesPositionalArg())
+    FS.setArgIndex(argIndex++);
+  // FreeBSD kernel specific.
+  if (k == ConversionSpecifier::FreeBSDbArg ||
+      k == ConversionSpecifier::FreeBSDDArg)
+    argIndex++;
+
+  if (k == ConversionSpecifier::InvalidSpecifier) {
+    unsigned Len = I - Start;
+    if (ParseUTF8InvalidSpecifier(Start, E, Len)) {
+      CS.setEndScanList(Start + Len);
+      FS.setConversionSpecifier(CS);
+    }
+    // Assume the conversion takes one argument.
+    return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
+  }
+  return PrintfSpecifierResult(Start, FS);
+}
+
+bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
+                                                     const char *I,
+                                                     const char *E,
+                                                     const LangOptions &LO,
+                                                     const TargetInfo &Target,
+                                                     bool isFreeBSDKPrintf) {
+
+  unsigned argIndex = 0;
+
+  // Keep looking for a format specifier until we have exhausted the string.
+  while (I != E) {
+    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
+                                                            LO, Target, true,
+                                                            isFreeBSDKPrintf);
+    // Did a fail-stop error of any kind occur when parsing the specifier?
+    // If so, don't do any more processing.
+    if (FSR.shouldStop())
+      return true;
+    // Did we exhaust the string or encounter an error that
+    // we can recover from?
+    if (!FSR.hasValue())
+      continue;
+    // We have a format specifier.  Pass it to the callback.
+    if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
+                                 I - FSR.getStart()))
+      return true;
+  }
+  assert(I == E && "Format string not exhausted");
+  return false;
+}
+
+bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
+                                                            const char *E,
+                                                            const LangOptions &LO,
+                                                            const TargetInfo &Target) {
+
+  unsigned argIndex = 0;
+
+  // Keep looking for a %s format specifier until we have exhausted the string.
+  FormatStringHandler H;
+  while (I != E) {
+    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
+                                                            LO, Target, false,
+                                                            false);
+    // Did a fail-stop error of any kind occur when parsing the specifier?
+    // If so, don't do any more processing.
+    if (FSR.shouldStop())
+      return false;
+    // Did we exhaust the string or encounter an error that
+    // we can recover from?
+    if (!FSR.hasValue())
+      continue;
+    const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
+    // Return true if this a %s format specifier.
+    if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)
+      return true;
+  }
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Methods on PrintfSpecifier.
+//===----------------------------------------------------------------------===//
+
+ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
+                                    bool IsObjCLiteral) const {
+  const PrintfConversionSpecifier &CS = getConversionSpecifier();
+
+  if (!CS.consumesDataArgument())
+    return ArgType::Invalid();
+
+  if (CS.getKind() == ConversionSpecifier::cArg)
+    switch (LM.getKind()) {
+      case LengthModifier::None:
+        return Ctx.IntTy;
+      case LengthModifier::AsLong:
+      case LengthModifier::AsWide:
+        return ArgType(ArgType::WIntTy, "wint_t");
+      case LengthModifier::AsShort:
+        if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
+          return Ctx.IntTy;
+        LLVM_FALLTHROUGH;
+      default:
+        return ArgType::Invalid();
+    }
+
+  if (CS.isIntArg())
+    switch (LM.getKind()) {
+      case LengthModifier::AsLongDouble:
+        // GNU extension.
+        return Ctx.LongLongTy;
+      case LengthModifier::None:
+        return Ctx.IntTy;
+      case LengthModifier::AsInt32:
+        return ArgType(Ctx.IntTy, "__int32");
+      case LengthModifier::AsChar: return ArgType::AnyCharTy;
+      case LengthModifier::AsShort: return Ctx.ShortTy;
+      case LengthModifier::AsLong: return Ctx.LongTy;
+      case LengthModifier::AsLongLong:
+      case LengthModifier::AsQuad:
+        return Ctx.LongLongTy;
+      case LengthModifier::AsInt64:
+        return ArgType(Ctx.LongLongTy, "__int64");
+      case LengthModifier::AsIntMax:
+        return ArgType(Ctx.getIntMaxType(), "intmax_t");
+      case LengthModifier::AsSizeT:
+        return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
+      case LengthModifier::AsInt3264:
+        return Ctx.getTargetInfo().getTriple().isArch64Bit()
+                   ? ArgType(Ctx.LongLongTy, "__int64")
+                   : ArgType(Ctx.IntTy, "__int32");
+      case LengthModifier::AsPtrDiff:
+        return ArgType::makePtrdiffT(
+            ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
+      case LengthModifier::AsAllocate:
+      case LengthModifier::AsMAllocate:
+      case LengthModifier::AsWide:
+        return ArgType::Invalid();
+    }
+
+  if (CS.isUIntArg())
+    switch (LM.getKind()) {
+      case LengthModifier::AsLongDouble:
+        // GNU extension.
+        return Ctx.UnsignedLongLongTy;
+      case LengthModifier::None:
+        return Ctx.UnsignedIntTy;
+      case LengthModifier::AsInt32:
+        return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
+      case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
+      case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
+      case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
+      case LengthModifier::AsLongLong:
+      case LengthModifier::AsQuad:
+        return Ctx.UnsignedLongLongTy;
+      case LengthModifier::AsInt64:
+        return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
+      case LengthModifier::AsIntMax:
+        return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
+      case LengthModifier::AsSizeT:
+        return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
+      case LengthModifier::AsInt3264:
+        return Ctx.getTargetInfo().getTriple().isArch64Bit()
+                   ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
+                   : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
+      case LengthModifier::AsPtrDiff:
+        return ArgType::makePtrdiffT(
+            ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
+      case LengthModifier::AsAllocate:
+      case LengthModifier::AsMAllocate:
+      case LengthModifier::AsWide:
+        return ArgType::Invalid();
+    }
+
+  if (CS.isDoubleArg()) {
+    if (LM.getKind() == LengthModifier::AsLongDouble)
+      return Ctx.LongDoubleTy;
+    return Ctx.DoubleTy;
+  }
+
+  if (CS.getKind() == ConversionSpecifier::nArg) {
+    switch (LM.getKind()) {
+      case LengthModifier::None:
+        return ArgType::PtrTo(Ctx.IntTy);
+      case LengthModifier::AsChar:
+        return ArgType::PtrTo(Ctx.SignedCharTy);
+      case LengthModifier::AsShort:
+        return ArgType::PtrTo(Ctx.ShortTy);
+      case LengthModifier::AsLong:
+        return ArgType::PtrTo(Ctx.LongTy);
+      case LengthModifier::AsLongLong:
+      case LengthModifier::AsQuad:
+        return ArgType::PtrTo(Ctx.LongLongTy);
+      case LengthModifier::AsIntMax:
+        return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
+      case LengthModifier::AsSizeT:
+        return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
+      case LengthModifier::AsPtrDiff:
+        return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
+      case LengthModifier::AsLongDouble:
+        return ArgType(); // FIXME: Is this a known extension?
+      case LengthModifier::AsAllocate:
+      case LengthModifier::AsMAllocate:
+      case LengthModifier::AsInt32:
+      case LengthModifier::AsInt3264:
+      case LengthModifier::AsInt64:
+      case LengthModifier::AsWide:
+        return ArgType::Invalid();
+    }
+  }
+
+  switch (CS.getKind()) {
+    case ConversionSpecifier::sArg:
+      if (LM.getKind() == LengthModifier::AsWideChar) {
+        if (IsObjCLiteral)
+          return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
+                         "const unichar *");
+        return ArgType(ArgType::WCStrTy, "wchar_t *");
+      }
+      if (LM.getKind() == LengthModifier::AsWide)
+        return ArgType(ArgType::WCStrTy, "wchar_t *");
+      return ArgType::CStrTy;
+    case ConversionSpecifier::SArg:
+      if (IsObjCLiteral)
+        return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
+                       "const unichar *");
+      if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
+          LM.getKind() == LengthModifier::AsShort)
+        return ArgType::CStrTy;
+      return ArgType(ArgType::WCStrTy, "wchar_t *");
+    case ConversionSpecifier::CArg:
+      if (IsObjCLiteral)
+        return ArgType(Ctx.UnsignedShortTy, "unichar");
+      if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
+          LM.getKind() == LengthModifier::AsShort)
+        return Ctx.IntTy;
+      return ArgType(Ctx.WideCharTy, "wchar_t");
+    case ConversionSpecifier::pArg:
+    case ConversionSpecifier::PArg:
+      return ArgType::CPointerTy;
+    case ConversionSpecifier::ObjCObjArg:
+      return ArgType::ObjCPointerTy;
+    default:
+      break;
+  }
+
+  // FIXME: Handle other cases.
+  return ArgType();
+}
+
+bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
+                              ASTContext &Ctx, bool IsObjCLiteral) {
+  // %n is different from other conversion specifiers; don't try to fix it.
+  if (CS.getKind() == ConversionSpecifier::nArg)
+    return false;
+
+  // Handle Objective-C objects first. Note that while the '%@' specifier will
+  // not warn for structure pointer or void pointer arguments (because that's
+  // how CoreFoundation objects are implemented), we only show a fixit for '%@'
+  // if we know it's an object (block, id, class, or __attribute__((NSObject))).
+  if (QT->isObjCRetainableType()) {
+    if (!IsObjCLiteral)
+      return false;
+
+    CS.setKind(ConversionSpecifier::ObjCObjArg);
+
+    // Disable irrelevant flags
+    HasThousandsGrouping = false;
+    HasPlusPrefix = false;
+    HasSpacePrefix = false;
+    HasAlternativeForm = false;
+    HasLeadingZeroes = false;
+    Precision.setHowSpecified(OptionalAmount::NotSpecified);
+    LM.setKind(LengthModifier::None);
+
+    return true;
+  }
+
+  // Handle strings next (char *, wchar_t *)
+  if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
+    CS.setKind(ConversionSpecifier::sArg);
+
+    // Disable irrelevant flags
+    HasAlternativeForm = 0;
+    HasLeadingZeroes = 0;
+
+    // Set the long length modifier for wide characters
+    if (QT->getPointeeType()->isWideCharType())
+      LM.setKind(LengthModifier::AsWideChar);
+    else
+      LM.setKind(LengthModifier::None);
+
+    return true;
+  }
+
+  // If it's an enum, get its underlying type.
+  if (const EnumType *ETy = QT->getAs<EnumType>())
+    QT = ETy->getDecl()->getIntegerType();
+
+  // We can only work with builtin types.
+  const BuiltinType *BT = QT->getAs<BuiltinType>();
+  if (!BT)
+    return false;
+
+  // Set length modifier
+  switch (BT->getKind()) {
+  case BuiltinType::Bool:
+  case BuiltinType::WChar_U:
+  case BuiltinType::WChar_S:
+  case BuiltinType::Char8: // FIXME: Treat like 'char'?
+  case BuiltinType::Char16:
+  case BuiltinType::Char32:
+  case BuiltinType::UInt128:
+  case BuiltinType::Int128:
+  case BuiltinType::Half:
+  case BuiltinType::Float16:
+  case BuiltinType::Float128:
+  case BuiltinType::ShortAccum:
+  case BuiltinType::Accum:
+  case BuiltinType::LongAccum:
+  case BuiltinType::UShortAccum:
+  case BuiltinType::UAccum:
+  case BuiltinType::ULongAccum:
+  case BuiltinType::ShortFract:
+  case BuiltinType::Fract:
+  case BuiltinType::LongFract:
+  case BuiltinType::UShortFract:
+  case BuiltinType::UFract:
+  case BuiltinType::ULongFract:
+  case BuiltinType::SatShortAccum:
+  case BuiltinType::SatAccum:
+  case BuiltinType::SatLongAccum:
+  case BuiltinType::SatUShortAccum:
+  case BuiltinType::SatUAccum:
+  case BuiltinType::SatULongAccum:
+  case BuiltinType::SatShortFract:
+  case BuiltinType::SatFract:
+  case BuiltinType::SatLongFract:
+  case BuiltinType::SatUShortFract:
+  case BuiltinType::SatUFract:
+  case BuiltinType::SatULongFract:
+    // Various types which are non-trivial to correct.
+    return false;
+
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+  case BuiltinType::Id:
+#include "clang/Basic/OpenCLImageTypes.def"
+#define SIGNED_TYPE(Id, SingletonId)
+#define UNSIGNED_TYPE(Id, SingletonId)
+#define FLOATING_TYPE(Id, SingletonId)
+#define BUILTIN_TYPE(Id, SingletonId) \
+  case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
+    // Misc other stuff which doesn't make sense here.
+    return false;
+
+  case BuiltinType::UInt:
+  case BuiltinType::Int:
+  case BuiltinType::Float:
+  case BuiltinType::Double:
+    LM.setKind(LengthModifier::None);
+    break;
+
+  case BuiltinType::Char_U:
+  case BuiltinType::UChar:
+  case BuiltinType::Char_S:
+  case BuiltinType::SChar:
+    LM.setKind(LengthModifier::AsChar);
+    break;
+
+  case BuiltinType::Short:
+  case BuiltinType::UShort:
+    LM.setKind(LengthModifier::AsShort);
+    break;
+
+  case BuiltinType::Long:
+  case BuiltinType::ULong:
+    LM.setKind(LengthModifier::AsLong);
+    break;
+
+  case BuiltinType::LongLong:
+  case BuiltinType::ULongLong:
+    LM.setKind(LengthModifier::AsLongLong);
+    break;
+
+  case BuiltinType::LongDouble:
+    LM.setKind(LengthModifier::AsLongDouble);
+    break;
+  }
+
+  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
+  if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
+    namedTypeToLengthModifier(QT, LM);
+
+  // If fixing the length modifier was enough, we might be done.
+  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+    // If we're going to offer a fix anyway, make sure the sign matches.
+    switch (CS.getKind()) {
+    case ConversionSpecifier::uArg:
+    case ConversionSpecifier::UArg:
+      if (QT->isSignedIntegerType())
+        CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
+      break;
+    case ConversionSpecifier::dArg:
+    case ConversionSpecifier::DArg:
+    case ConversionSpecifier::iArg:
+      if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
+        CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
+      break;
+    default:
+      // Other specifiers do not have signed/unsigned variants.
+      break;
+    }
+
+    const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
+    if (ATR.isValid() && ATR.matchesType(Ctx, QT))
+      return true;
+  }
+
+  // Set conversion specifier and disable any flags which do not apply to it.
+  // Let typedefs to char fall through to int, as %c is silly for uint8_t.
+  if (!isa<TypedefType>(QT) && QT->isCharType()) {
+    CS.setKind(ConversionSpecifier::cArg);
+    LM.setKind(LengthModifier::None);
+    Precision.setHowSpecified(OptionalAmount::NotSpecified);
+    HasAlternativeForm = 0;
+    HasLeadingZeroes = 0;
+    HasPlusPrefix = 0;
+  }
+  // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
+  else if (QT->isRealFloatingType()) {
+    CS.setKind(ConversionSpecifier::fArg);
+  }
+  else if (QT->isSignedIntegerType()) {
+    CS.setKind(ConversionSpecifier::dArg);
+    HasAlternativeForm = 0;
+  }
+  else if (QT->isUnsignedIntegerType()) {
+    CS.setKind(ConversionSpecifier::uArg);
+    HasAlternativeForm = 0;
+    HasPlusPrefix = 0;
+  } else {
+    llvm_unreachable("Unexpected type");
+  }
+
+  return true;
+}
+
+void PrintfSpecifier::toString(raw_ostream &os) const {
+  // Whilst some features have no defined order, we are using the order
+  // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
+  os << "%";
+
+  // Positional args
+  if (usesPositionalArg()) {
+    os << getPositionalArgIndex() << "$";
+  }
+
+  // Conversion flags
+  if (IsLeftJustified)    os << "-";
+  if (HasPlusPrefix)      os << "+";
+  if (HasSpacePrefix)     os << " ";
+  if (HasAlternativeForm) os << "#";
+  if (HasLeadingZeroes)   os << "0";
+
+  // Minimum field width
+  FieldWidth.toString(os);
+  // Precision
+  Precision.toString(os);
+  // Length modifier
+  os << LM.toString();
+  // Conversion specifier
+  os << CS.toString();
+}
+
+bool PrintfSpecifier::hasValidPlusPrefix() const {
+  if (!HasPlusPrefix)
+    return true;
+
+  // The plus prefix only makes sense for signed conversions
+  switch (CS.getKind()) {
+  case ConversionSpecifier::dArg:
+  case ConversionSpecifier::DArg:
+  case ConversionSpecifier::iArg:
+  case ConversionSpecifier::fArg:
+  case ConversionSpecifier::FArg:
+  case ConversionSpecifier::eArg:
+  case ConversionSpecifier::EArg:
+  case ConversionSpecifier::gArg:
+  case ConversionSpecifier::GArg:
+  case ConversionSpecifier::aArg:
+  case ConversionSpecifier::AArg:
+  case ConversionSpecifier::FreeBSDrArg:
+  case ConversionSpecifier::FreeBSDyArg:
+    return true;
+
+  default:
+    return false;
+  }
+}
+
+bool PrintfSpecifier::hasValidAlternativeForm() const {
+  if (!HasAlternativeForm)
+    return true;
+
+  // Alternate form flag only valid with the oxXaAeEfFgG conversions
+  switch (CS.getKind()) {
+  case ConversionSpecifier::oArg:
+  case ConversionSpecifier::OArg:
+  case ConversionSpecifier::xArg:
+  case ConversionSpecifier::XArg:
+  case ConversionSpecifier::aArg:
+  case ConversionSpecifier::AArg:
+  case ConversionSpecifier::eArg:
+  case ConversionSpecifier::EArg:
+  case ConversionSpecifier::fArg:
+  case ConversionSpecifier::FArg:
+  case ConversionSpecifier::gArg:
+  case ConversionSpecifier::GArg:
+  case ConversionSpecifier::FreeBSDrArg:
+  case ConversionSpecifier::FreeBSDyArg:
+    return true;
+
+  default:
+    return false;
+  }
+}
+
+bool PrintfSpecifier::hasValidLeadingZeros() const {
+  if (!HasLeadingZeroes)
+    return true;
+
+  // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
+  switch (CS.getKind()) {
+  case ConversionSpecifier::dArg:
+  case ConversionSpecifier::DArg:
+  case ConversionSpecifier::iArg:
+  case ConversionSpecifier::oArg:
+  case ConversionSpecifier::OArg:
+  case ConversionSpecifier::uArg:
+  case ConversionSpecifier::UArg:
+  case ConversionSpecifier::xArg:
+  case ConversionSpecifier::XArg:
+  case ConversionSpecifier::aArg:
+  case ConversionSpecifier::AArg:
+  case ConversionSpecifier::eArg:
+  case ConversionSpecifier::EArg:
+  case ConversionSpecifier::fArg:
+  case ConversionSpecifier::FArg:
+  case ConversionSpecifier::gArg:
+  case ConversionSpecifier::GArg:
+  case ConversionSpecifier::FreeBSDrArg:
+  case ConversionSpecifier::FreeBSDyArg:
+    return true;
+
+  default:
+    return false;
+  }
+}
+
+bool PrintfSpecifier::hasValidSpacePrefix() const {
+  if (!HasSpacePrefix)
+    return true;
+
+  // The space prefix only makes sense for signed conversions
+  switch (CS.getKind()) {
+  case ConversionSpecifier::dArg:
+  case ConversionSpecifier::DArg:
+  case ConversionSpecifier::iArg:
+  case ConversionSpecifier::fArg:
+  case ConversionSpecifier::FArg:
+  case ConversionSpecifier::eArg:
+  case ConversionSpecifier::EArg:
+  case ConversionSpecifier::gArg:
+  case ConversionSpecifier::GArg:
+  case ConversionSpecifier::aArg:
+  case ConversionSpecifier::AArg:
+  case ConversionSpecifier::FreeBSDrArg:
+  case ConversionSpecifier::FreeBSDyArg:
+    return true;
+
+  default:
+    return false;
+  }
+}
+
+bool PrintfSpecifier::hasValidLeftJustified() const {
+  if (!IsLeftJustified)
+    return true;
+
+  // The left justified flag is valid for all conversions except n
+  switch (CS.getKind()) {
+  case ConversionSpecifier::nArg:
+    return false;
+
+  default:
+    return true;
+  }
+}
+
+bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
+  if (!HasThousandsGrouping)
+    return true;
+
+  switch (CS.getKind()) {
+    case ConversionSpecifier::dArg:
+    case ConversionSpecifier::DArg:
+    case ConversionSpecifier::iArg:
+    case ConversionSpecifier::uArg:
+    case ConversionSpecifier::UArg:
+    case ConversionSpecifier::fArg:
+    case ConversionSpecifier::FArg:
+    case ConversionSpecifier::gArg:
+    case ConversionSpecifier::GArg:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool PrintfSpecifier::hasValidPrecision() const {
+  if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
+    return true;
+
+  // Precision is only valid with the diouxXaAeEfFgGsP conversions
+  switch (CS.getKind()) {
+  case ConversionSpecifier::dArg:
+  case ConversionSpecifier::DArg:
+  case ConversionSpecifier::iArg:
+  case ConversionSpecifier::oArg:
+  case ConversionSpecifier::OArg:
+  case ConversionSpecifier::uArg:
+  case ConversionSpecifier::UArg:
+  case ConversionSpecifier::xArg:
+  case ConversionSpecifier::XArg:
+  case ConversionSpecifier::aArg:
+  case ConversionSpecifier::AArg:
+  case ConversionSpecifier::eArg:
+  case ConversionSpecifier::EArg:
+  case ConversionSpecifier::fArg:
+  case ConversionSpecifier::FArg:
+  case ConversionSpecifier::gArg:
+  case ConversionSpecifier::GArg:
+  case ConversionSpecifier::sArg:
+  case ConversionSpecifier::FreeBSDrArg:
+  case ConversionSpecifier::FreeBSDyArg:
+  case ConversionSpecifier::PArg:
+    return true;
+
+  default:
+    return false;
+  }
+}
+bool PrintfSpecifier::hasValidFieldWidth() const {
+  if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
+      return true;
+
+  // The field width is valid for all conversions except n
+  switch (CS.getKind()) {
+  case ConversionSpecifier::nArg:
+    return false;
+
+  default:
+    return true;
+  }
+}

Added: cfe/trunk/lib/AST/ScanfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ScanfFormatString.cpp?rev=345971&view=auto
==============================================================================
--- cfe/trunk/lib/AST/ScanfFormatString.cpp (added)
+++ cfe/trunk/lib/AST/ScanfFormatString.cpp Fri Nov  2 06:14:11 2018
@@ -0,0 +1,563 @@
+//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handling of format string in scanf and friends.  The structure of format
+// strings for fscanf() are described in C99 7.19.6.2.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/FormatString.h"
+#include "FormatStringParsing.h"
+#include "clang/Basic/TargetInfo.h"
+
+using clang::analyze_format_string::ArgType;
+using clang::analyze_format_string::FormatStringHandler;
+using clang::analyze_format_string::LengthModifier;
+using clang::analyze_format_string::OptionalAmount;
+using clang::analyze_format_string::ConversionSpecifier;
+using clang::analyze_scanf::ScanfConversionSpecifier;
+using clang::analyze_scanf::ScanfSpecifier;
+using clang::UpdateOnReturn;
+using namespace clang;
+
+typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
+        ScanfSpecifierResult;
+
+static bool ParseScanList(FormatStringHandler &H,
+                          ScanfConversionSpecifier &CS,
+                          const char *&Beg, const char *E) {
+  const char *I = Beg;
+  const char *start = I - 1;
+  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
+
+  // No more characters?
+  if (I == E) {
+    H.HandleIncompleteScanList(start, I);
+    return true;
+  }
+
+  // Special case: ']' is the first character.
+  if (*I == ']') {
+    if (++I == E) {
+      H.HandleIncompleteScanList(start, I - 1);
+      return true;
+    }
+  }
+
+  // Special case: "^]" are the first characters.
+  if (I + 1 != E && I[0] == '^' && I[1] == ']') {
+    I += 2;
+    if (I == E) {
+      H.HandleIncompleteScanList(start, I - 1);
+      return true;
+    }
+  }
+
+  // Look for a ']' character which denotes the end of the scan list.
+  while (*I != ']') {
+    if (++I == E) {
+      H.HandleIncompleteScanList(start, I - 1);
+      return true;
+    }
+  }
+
+  CS.setEndScanList(I);
+  return false;
+}
+
+// FIXME: Much of this is copy-paste from ParsePrintfSpecifier.
+// We can possibly refactor.
+static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
+                                                const char *&Beg,
+                                                const char *E,
+                                                unsigned &argIndex,
+                                                const LangOptions &LO,
+                                                const TargetInfo &Target) {
+  using namespace clang::analyze_format_string;
+  using namespace clang::analyze_scanf;
+  const char *I = Beg;
+  const char *Start = nullptr;
+  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
+
+    // Look for a '%' character that indicates the start of a format specifier.
+  for ( ; I != E ; ++I) {
+    char c = *I;
+    if (c == '\0') {
+        // Detect spurious null characters, which are likely errors.
+      H.HandleNullChar(I);
+      return true;
+    }
+    if (c == '%') {
+      Start = I++;  // Record the start of the format specifier.
+      break;
+    }
+  }
+
+    // No format specifier found?
+  if (!Start)
+    return false;
+
+  if (I == E) {
+      // No more characters left?
+    H.HandleIncompleteSpecifier(Start, E - Start);
+    return true;
+  }
+
+  ScanfSpecifier FS;
+  if (ParseArgPosition(H, FS, Start, I, E))
+    return true;
+
+  if (I == E) {
+      // No more characters left?
+    H.HandleIncompleteSpecifier(Start, E - Start);
+    return true;
+  }
+
+  // Look for '*' flag if it is present.
+  if (*I == '*') {
+    FS.setSuppressAssignment(I);
+    if (++I == E) {
+      H.HandleIncompleteSpecifier(Start, E - Start);
+      return true;
+    }
+  }
+
+  // Look for the field width (if any).  Unlike printf, this is either
+  // a fixed integer or isn't present.
+  const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E);
+  if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
+    assert(Amt.getHowSpecified() == OptionalAmount::Constant);
+    FS.setFieldWidth(Amt);
+
+    if (I == E) {
+      // No more characters left?
+      H.HandleIncompleteSpecifier(Start, E - Start);
+      return true;
+    }
+  }
+
+  // Look for the length modifier.
+  if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) {
+      // No more characters left?
+    H.HandleIncompleteSpecifier(Start, E - Start);
+    return true;
+  }
+
+  // Detect spurious null characters, which are likely errors.
+  if (*I == '\0') {
+    H.HandleNullChar(I);
+    return true;
+  }
+
+  // Finally, look for the conversion specifier.
+  const char *conversionPosition = I++;
+  ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;
+  switch (*conversionPosition) {
+    default:
+      break;
+    case '%': k = ConversionSpecifier::PercentArg;   break;
+    case 'A': k = ConversionSpecifier::AArg; break;
+    case 'E': k = ConversionSpecifier::EArg; break;
+    case 'F': k = ConversionSpecifier::FArg; break;
+    case 'G': k = ConversionSpecifier::GArg; break;
+    case 'X': k = ConversionSpecifier::XArg; break;
+    case 'a': k = ConversionSpecifier::aArg; break;
+    case 'd': k = ConversionSpecifier::dArg; break;
+    case 'e': k = ConversionSpecifier::eArg; break;
+    case 'f': k = ConversionSpecifier::fArg; break;
+    case 'g': k = ConversionSpecifier::gArg; break;
+    case 'i': k = ConversionSpecifier::iArg; break;
+    case 'n': k = ConversionSpecifier::nArg; break;
+    case 'c': k = ConversionSpecifier::cArg; break;
+    case 'C': k = ConversionSpecifier::CArg; break;
+    case 'S': k = ConversionSpecifier::SArg; break;
+    case '[': k = ConversionSpecifier::ScanListArg; break;
+    case 'u': k = ConversionSpecifier::uArg; break;
+    case 'x': k = ConversionSpecifier::xArg; break;
+    case 'o': k = ConversionSpecifier::oArg; break;
+    case 's': k = ConversionSpecifier::sArg; break;
+    case 'p': k = ConversionSpecifier::pArg; break;
+    // Apple extensions
+      // Apple-specific
+    case 'D':
+      if (Target.getTriple().isOSDarwin())
+        k = ConversionSpecifier::DArg;
+      break;
+    case 'O':
+      if (Target.getTriple().isOSDarwin())
+        k = ConversionSpecifier::OArg;
+      break;
+    case 'U':
+      if (Target.getTriple().isOSDarwin())
+        k = ConversionSpecifier::UArg;
+      break;
+  }
+  ScanfConversionSpecifier CS(conversionPosition, k);
+  if (k == ScanfConversionSpecifier::ScanListArg) {
+    if (ParseScanList(H, CS, I, E))
+      return true;
+  }
+  FS.setConversionSpecifier(CS);
+  if (CS.consumesDataArgument() && !FS.getSuppressAssignment()
+      && !FS.usesPositionalArg())
+    FS.setArgIndex(argIndex++);
+
+  // FIXME: '%' and '*' doesn't make sense.  Issue a warning.
+  // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.
+
+  if (k == ScanfConversionSpecifier::InvalidSpecifier) {
+    unsigned Len = I - Beg;
+    if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {
+      CS.setEndScanList(Beg + Len);
+      FS.setConversionSpecifier(CS);
+    }
+    // Assume the conversion takes one argument.
+    return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);
+  }
+  return ScanfSpecifierResult(Start, FS);
+}
+
+ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
+  const ScanfConversionSpecifier &CS = getConversionSpecifier();
+
+  if (!CS.consumesDataArgument())
+    return ArgType::Invalid();
+
+  switch(CS.getKind()) {
+    // Signed int.
+    case ConversionSpecifier::dArg:
+    case ConversionSpecifier::DArg:
+    case ConversionSpecifier::iArg:
+      switch (LM.getKind()) {
+        case LengthModifier::None:
+          return ArgType::PtrTo(Ctx.IntTy);
+        case LengthModifier::AsChar:
+          return ArgType::PtrTo(ArgType::AnyCharTy);
+        case LengthModifier::AsShort:
+          return ArgType::PtrTo(Ctx.ShortTy);
+        case LengthModifier::AsLong:
+          return ArgType::PtrTo(Ctx.LongTy);
+        case LengthModifier::AsLongLong:
+        case LengthModifier::AsQuad:
+          return ArgType::PtrTo(Ctx.LongLongTy);
+        case LengthModifier::AsInt64:
+          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
+        case LengthModifier::AsIntMax:
+          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
+        case LengthModifier::AsSizeT:
+          return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
+        case LengthModifier::AsPtrDiff:
+          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
+        case LengthModifier::AsLongDouble:
+          // GNU extension.
+          return ArgType::PtrTo(Ctx.LongLongTy);
+        case LengthModifier::AsAllocate:
+        case LengthModifier::AsMAllocate:
+        case LengthModifier::AsInt32:
+        case LengthModifier::AsInt3264:
+        case LengthModifier::AsWide:
+          return ArgType::Invalid();
+      }
+
+    // Unsigned int.
+    case ConversionSpecifier::oArg:
+    case ConversionSpecifier::OArg:
+    case ConversionSpecifier::uArg:
+    case ConversionSpecifier::UArg:
+    case ConversionSpecifier::xArg:
+    case ConversionSpecifier::XArg:
+      switch (LM.getKind()) {
+        case LengthModifier::None:
+          return ArgType::PtrTo(Ctx.UnsignedIntTy);
+        case LengthModifier::AsChar:
+          return ArgType::PtrTo(Ctx.UnsignedCharTy);
+        case LengthModifier::AsShort:
+          return ArgType::PtrTo(Ctx.UnsignedShortTy);
+        case LengthModifier::AsLong:
+          return ArgType::PtrTo(Ctx.UnsignedLongTy);
+        case LengthModifier::AsLongLong:
+        case LengthModifier::AsQuad:
+          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
+        case LengthModifier::AsInt64:
+          return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"));
+        case LengthModifier::AsIntMax:
+          return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
+        case LengthModifier::AsSizeT:
+          return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
+        case LengthModifier::AsPtrDiff:
+          return ArgType::PtrTo(
+              ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
+        case LengthModifier::AsLongDouble:
+          // GNU extension.
+          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
+        case LengthModifier::AsAllocate:
+        case LengthModifier::AsMAllocate:
+        case LengthModifier::AsInt32:
+        case LengthModifier::AsInt3264:
+        case LengthModifier::AsWide:
+          return ArgType::Invalid();
+      }
+
+    // Float.
+    case ConversionSpecifier::aArg:
+    case ConversionSpecifier::AArg:
+    case ConversionSpecifier::eArg:
+    case ConversionSpecifier::EArg:
+    case ConversionSpecifier::fArg:
+    case ConversionSpecifier::FArg:
+    case ConversionSpecifier::gArg:
+    case ConversionSpecifier::GArg:
+      switch (LM.getKind()) {
+        case LengthModifier::None:
+          return ArgType::PtrTo(Ctx.FloatTy);
+        case LengthModifier::AsLong:
+          return ArgType::PtrTo(Ctx.DoubleTy);
+        case LengthModifier::AsLongDouble:
+          return ArgType::PtrTo(Ctx.LongDoubleTy);
+        default:
+          return ArgType::Invalid();
+      }
+
+    // Char, string and scanlist.
+    case ConversionSpecifier::cArg:
+    case ConversionSpecifier::sArg:
+    case ConversionSpecifier::ScanListArg:
+      switch (LM.getKind()) {
+        case LengthModifier::None:
+          return ArgType::PtrTo(ArgType::AnyCharTy);
+        case LengthModifier::AsLong:
+        case LengthModifier::AsWide:
+          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
+        case LengthModifier::AsAllocate:
+        case LengthModifier::AsMAllocate:
+          return ArgType::PtrTo(ArgType::CStrTy);
+        case LengthModifier::AsShort:
+          if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
+            return ArgType::PtrTo(ArgType::AnyCharTy);
+          LLVM_FALLTHROUGH;
+        default:
+          return ArgType::Invalid();
+      }
+    case ConversionSpecifier::CArg:
+    case ConversionSpecifier::SArg:
+      // FIXME: Mac OS X specific?
+      switch (LM.getKind()) {
+        case LengthModifier::None:
+        case LengthModifier::AsWide:
+          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
+        case LengthModifier::AsAllocate:
+        case LengthModifier::AsMAllocate:
+          return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
+        case LengthModifier::AsShort:
+          if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
+            return ArgType::PtrTo(ArgType::AnyCharTy);
+          LLVM_FALLTHROUGH;
+        default:
+          return ArgType::Invalid();
+      }
+
+    // Pointer.
+    case ConversionSpecifier::pArg:
+      return ArgType::PtrTo(ArgType::CPointerTy);
+
+    // Write-back.
+    case ConversionSpecifier::nArg:
+      switch (LM.getKind()) {
+        case LengthModifier::None:
+          return ArgType::PtrTo(Ctx.IntTy);
+        case LengthModifier::AsChar:
+          return ArgType::PtrTo(Ctx.SignedCharTy);
+        case LengthModifier::AsShort:
+          return ArgType::PtrTo(Ctx.ShortTy);
+        case LengthModifier::AsLong:
+          return ArgType::PtrTo(Ctx.LongTy);
+        case LengthModifier::AsLongLong:
+        case LengthModifier::AsQuad:
+          return ArgType::PtrTo(Ctx.LongLongTy);
+        case LengthModifier::AsInt64:
+          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
+        case LengthModifier::AsIntMax:
+          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
+        case LengthModifier::AsSizeT:
+          return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
+        case LengthModifier::AsPtrDiff:
+          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
+        case LengthModifier::AsLongDouble:
+          return ArgType(); // FIXME: Is this a known extension?
+        case LengthModifier::AsAllocate:
+        case LengthModifier::AsMAllocate:
+        case LengthModifier::AsInt32:
+        case LengthModifier::AsInt3264:
+        case LengthModifier::AsWide:
+          return ArgType::Invalid();
+        }
+
+    default:
+      break;
+  }
+
+  return ArgType();
+}
+
+bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
+                             const LangOptions &LangOpt,
+                             ASTContext &Ctx) {
+
+  // %n is different from other conversion specifiers; don't try to fix it.
+  if (CS.getKind() == ConversionSpecifier::nArg)
+    return false;
+
+  if (!QT->isPointerType())
+    return false;
+
+  QualType PT = QT->getPointeeType();
+
+  // If it's an enum, get its underlying type.
+  if (const EnumType *ETy = PT->getAs<EnumType>()) {
+    // Don't try to fix incomplete enums.
+    if (!ETy->getDecl()->isComplete())
+      return false;
+    PT = ETy->getDecl()->getIntegerType();
+  }
+
+  const BuiltinType *BT = PT->getAs<BuiltinType>();
+  if (!BT)
+    return false;
+
+  // Pointer to a character.
+  if (PT->isAnyCharacterType()) {
+    CS.setKind(ConversionSpecifier::sArg);
+    if (PT->isWideCharType())
+      LM.setKind(LengthModifier::AsWideChar);
+    else
+      LM.setKind(LengthModifier::None);
+
+    // If we know the target array length, we can use it as a field width.
+    if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) {
+      if (CAT->getSizeModifier() == ArrayType::Normal)
+        FieldWidth = OptionalAmount(OptionalAmount::Constant,
+                                    CAT->getSize().getZExtValue() - 1,
+                                    "", 0, false);
+
+    }
+    return true;
+  }
+
+  // Figure out the length modifier.
+  switch (BT->getKind()) {
+    // no modifier
+    case BuiltinType::UInt:
+    case BuiltinType::Int:
+    case BuiltinType::Float:
+      LM.setKind(LengthModifier::None);
+      break;
+
+    // hh
+    case BuiltinType::Char_U:
+    case BuiltinType::UChar:
+    case BuiltinType::Char_S:
+    case BuiltinType::SChar:
+      LM.setKind(LengthModifier::AsChar);
+      break;
+
+    // h
+    case BuiltinType::Short:
+    case BuiltinType::UShort:
+      LM.setKind(LengthModifier::AsShort);
+      break;
+
+    // l
+    case BuiltinType::Long:
+    case BuiltinType::ULong:
+    case BuiltinType::Double:
+      LM.setKind(LengthModifier::AsLong);
+      break;
+
+    // ll
+    case BuiltinType::LongLong:
+    case BuiltinType::ULongLong:
+      LM.setKind(LengthModifier::AsLongLong);
+      break;
+
+    // L
+    case BuiltinType::LongDouble:
+      LM.setKind(LengthModifier::AsLongDouble);
+      break;
+
+    // Don't know.
+    default:
+      return false;
+  }
+
+  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
+  if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
+    namedTypeToLengthModifier(PT, LM);
+
+  // If fixing the length modifier was enough, we are done.
+  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+    const analyze_scanf::ArgType &AT = getArgType(Ctx);
+    if (AT.isValid() && AT.matchesType(Ctx, QT))
+      return true;
+  }
+
+  // Figure out the conversion specifier.
+  if (PT->isRealFloatingType())
+    CS.setKind(ConversionSpecifier::fArg);
+  else if (PT->isSignedIntegerType())
+    CS.setKind(ConversionSpecifier::dArg);
+  else if (PT->isUnsignedIntegerType())
+    CS.setKind(ConversionSpecifier::uArg);
+  else
+    llvm_unreachable("Unexpected type");
+
+  return true;
+}
+
+void ScanfSpecifier::toString(raw_ostream &os) const {
+  os << "%";
+
+  if (usesPositionalArg())
+    os << getPositionalArgIndex() << "$";
+  if (SuppressAssignment)
+    os << "*";
+
+  FieldWidth.toString(os);
+  os << LM.toString();
+  os << CS.toString();
+}
+
+bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
+                                                    const char *I,
+                                                    const char *E,
+                                                    const LangOptions &LO,
+                                                    const TargetInfo &Target) {
+
+  unsigned argIndex = 0;
+
+  // Keep looking for a format specifier until we have exhausted the string.
+  while (I != E) {
+    const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
+                                                          LO, Target);
+    // Did a fail-stop error of any kind occur when parsing the specifier?
+    // If so, don't do any more processing.
+    if (FSR.shouldStop())
+      return true;
+      // Did we exhaust the string or encounter an error that
+      // we can recover from?
+    if (!FSR.hasValue())
+      continue;
+      // We have a format specifier.  Pass it to the callback.
+    if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
+                                I - FSR.getStart())) {
+      return true;
+    }
+  }
+  assert(I == E && "Format string not exhausted");
+  return false;
+}

Modified: cfe/trunk/lib/Analysis/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=345971&r1=345970&r2=345971&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CMakeLists.txt (original)
+++ cfe/trunk/lib/Analysis/CMakeLists.txt Fri Nov  2 06:14:11 2018
@@ -16,15 +16,11 @@ add_clang_library(clangAnalysis
   CodeInjector.cpp
   Dominators.cpp
   ExprMutationAnalyzer.cpp
-  FormatString.cpp
   LiveVariables.cpp
-  OSLog.cpp
   ObjCNoReturn.cpp
   PostOrderCFGView.cpp
-  PrintfFormatString.cpp
   ProgramPoint.cpp
   ReachableCode.cpp
-  ScanfFormatString.cpp
   ThreadSafety.cpp
   ThreadSafetyCommon.cpp
   ThreadSafetyLogical.cpp

Removed: cfe/trunk/lib/Analysis/FormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatString.cpp?rev=345970&view=auto
==============================================================================
--- cfe/trunk/lib/Analysis/FormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/FormatString.cpp (removed)
@@ -1,955 +0,0 @@
-// FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Shared details for processing format strings of printf and scanf
-// (and friends).
-//
-//===----------------------------------------------------------------------===//
-
-#include "FormatStringParsing.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/TargetInfo.h"
-#include "llvm/Support/ConvertUTF.h"
-
-using clang::analyze_format_string::ArgType;
-using clang::analyze_format_string::FormatStringHandler;
-using clang::analyze_format_string::FormatSpecifier;
-using clang::analyze_format_string::LengthModifier;
-using clang::analyze_format_string::OptionalAmount;
-using clang::analyze_format_string::PositionContext;
-using clang::analyze_format_string::ConversionSpecifier;
-using namespace clang;
-
-// Key function to FormatStringHandler.
-FormatStringHandler::~FormatStringHandler() {}
-
-//===----------------------------------------------------------------------===//
-// Functions for parsing format strings components in both printf and
-// scanf format strings.
-//===----------------------------------------------------------------------===//
-
-OptionalAmount
-clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) {
-  const char *I = Beg;
-  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
-
-  unsigned accumulator = 0;
-  bool hasDigits = false;
-
-  for ( ; I != E; ++I) {
-    char c = *I;
-    if (c >= '0' && c <= '9') {
-      hasDigits = true;
-      accumulator = (accumulator * 10) + (c - '0');
-      continue;
-    }
-
-    if (hasDigits)
-      return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,
-          false);
-
-    break;
-  }
-
-  return OptionalAmount();
-}
-
-OptionalAmount
-clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,
-                                                     const char *E,
-                                                     unsigned &argIndex) {
-  if (*Beg == '*') {
-    ++Beg;
-    return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
-  }
-
-  return ParseAmount(Beg, E);
-}
-
-OptionalAmount
-clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,
-                                                  const char *Start,
-                                                  const char *&Beg,
-                                                  const char *E,
-                                                  PositionContext p) {
-  if (*Beg == '*') {
-    const char *I = Beg + 1;
-    const OptionalAmount &Amt = ParseAmount(I, E);
-
-    if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
-      H.HandleInvalidPosition(Beg, I - Beg, p);
-      return OptionalAmount(false);
-    }
-
-    if (I == E) {
-      // No more characters left?
-      H.HandleIncompleteSpecifier(Start, E - Start);
-      return OptionalAmount(false);
-    }
-
-    assert(Amt.getHowSpecified() == OptionalAmount::Constant);
-
-    if (*I == '$') {
-      // Handle positional arguments
-
-      // Special case: '*0$', since this is an easy mistake.
-      if (Amt.getConstantAmount() == 0) {
-        H.HandleZeroPosition(Beg, I - Beg + 1);
-        return OptionalAmount(false);
-      }
-
-      const char *Tmp = Beg;
-      Beg = ++I;
-
-      return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
-                            Tmp, 0, true);
-    }
-
-    H.HandleInvalidPosition(Beg, I - Beg, p);
-    return OptionalAmount(false);
-  }
-
-  return ParseAmount(Beg, E);
-}
-
-
-bool
-clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,
-                                              FormatSpecifier &CS,
-                                              const char *Start,
-                                              const char *&Beg, const char *E,
-                                              unsigned *argIndex) {
-  // FIXME: Support negative field widths.
-  if (argIndex) {
-    CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
-  }
-  else {
-    const OptionalAmount Amt =
-      ParsePositionAmount(H, Start, Beg, E,
-                          analyze_format_string::FieldWidthPos);
-
-    if (Amt.isInvalid())
-      return true;
-    CS.setFieldWidth(Amt);
-  }
-  return false;
-}
-
-bool
-clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
-                                               FormatSpecifier &FS,
-                                               const char *Start,
-                                               const char *&Beg,
-                                               const char *E) {
-  const char *I = Beg;
-
-  const OptionalAmount &Amt = ParseAmount(I, E);
-
-  if (I == E) {
-    // No more characters left?
-    H.HandleIncompleteSpecifier(Start, E - Start);
-    return true;
-  }
-
-  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);
-      return true;
-    }
-
-    FS.setArgIndex(Amt.getConstantAmount() - 1);
-    FS.setUsesPositionalArg();
-    // Update the caller's pointer if we decided to consume
-    // these characters.
-    Beg = I;
-    return false;
-  }
-
-  return false;
-}
-
-bool
-clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
-                                                  const char *&I,
-                                                  const char *E,
-                                                  const LangOptions &LO,
-                                                  bool IsScanf) {
-  LengthModifier::Kind lmKind = LengthModifier::None;
-  const char *lmPosition = I;
-  switch (*I) {
-    default:
-      return false;
-    case 'h':
-      ++I;
-      if (I != E && *I == 'h') {
-        ++I;
-        lmKind = LengthModifier::AsChar;
-      } else {
-        lmKind = LengthModifier::AsShort;
-      }
-      break;
-    case 'l':
-      ++I;
-      if (I != E && *I == 'l') {
-        ++I;
-        lmKind = LengthModifier::AsLongLong;
-      } else {
-        lmKind = LengthModifier::AsLong;
-      }
-      break;
-    case 'j': lmKind = LengthModifier::AsIntMax;     ++I; break;
-    case 'z': lmKind = LengthModifier::AsSizeT;      ++I; break;
-    case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;
-    case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
-    case 'q': lmKind = LengthModifier::AsQuad;       ++I; break;
-    case 'a':
-      if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
-        // 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;
-    case 'm':
-      if (IsScanf) {
-        lmKind = LengthModifier::AsMAllocate;
-        ++I;
-        break;
-      }
-      return false;
-    // printf: AsInt64, AsInt32, AsInt3264
-    // scanf:  AsInt64
-    case 'I':
-      if (I + 1 != E && I + 2 != E) {
-        if (I[1] == '6' && I[2] == '4') {
-          I += 3;
-          lmKind = LengthModifier::AsInt64;
-          break;
-        }
-        if (IsScanf)
-          return false;
-
-        if (I[1] == '3' && I[2] == '2') {
-          I += 3;
-          lmKind = LengthModifier::AsInt32;
-          break;
-        }
-      }
-      ++I;
-      lmKind = LengthModifier::AsInt3264;
-      break;
-    case 'w':
-      lmKind = LengthModifier::AsWide; ++I; break;
-  }
-  LengthModifier lm(lmPosition, lmKind);
-  FS.setLengthModifier(lm);
-  return true;
-}
-
-bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
-    const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {
-  if (SpecifierBegin + 1 >= FmtStrEnd)
-    return false;
-
-  const llvm::UTF8 *SB =
-      reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);
-  const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);
-  const char FirstByte = *SB;
-
-  // If the invalid specifier is a multibyte UTF-8 string, return the
-  // total length accordingly so that the conversion specifier can be
-  // properly updated to reflect a complete UTF-8 specifier.
-  unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);
-  if (NumBytes == 1)
-    return false;
-  if (SB + NumBytes > SE)
-    return false;
-
-  Len = NumBytes + 1;
-  return true;
-}
-
-//===----------------------------------------------------------------------===//
-// Methods on ArgType.
-//===----------------------------------------------------------------------===//
-
-clang::analyze_format_string::ArgType::MatchKind
-ArgType::matchesType(ASTContext &C, QualType argTy) const {
-  if (Ptr) {
-    // It has to be a pointer.
-    const PointerType *PT = argTy->getAs<PointerType>();
-    if (!PT)
-      return NoMatch;
-
-    // We cannot write through a const qualified pointer.
-    if (PT->getPointeeType().isConstQualified())
-      return NoMatch;
-
-    argTy = PT->getPointeeType();
-  }
-
-  switch (K) {
-    case InvalidTy:
-      llvm_unreachable("ArgType must be valid");
-
-    case UnknownTy:
-      return Match;
-
-    case AnyCharTy: {
-      if (const EnumType *ETy = argTy->getAs<EnumType>()) {
-        // If the enum is incomplete we know nothing about the underlying type.
-        // Assume that it's 'int'.
-        if (!ETy->getDecl()->isComplete())
-          return NoMatch;
-        argTy = ETy->getDecl()->getIntegerType();
-      }
-
-      if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
-        switch (BT->getKind()) {
-          default:
-            break;
-          case BuiltinType::Char_S:
-          case BuiltinType::SChar:
-          case BuiltinType::UChar:
-          case BuiltinType::Char_U:
-            return Match;
-        }
-      return NoMatch;
-    }
-
-    case SpecificTy: {
-      if (const EnumType *ETy = argTy->getAs<EnumType>()) {
-        // If the enum is incomplete we know nothing about the underlying type.
-        // Assume that it's 'int'.
-        if (!ETy->getDecl()->isComplete())
-          argTy = C.IntTy;
-        else
-          argTy = ETy->getDecl()->getIntegerType();
-      }
-      argTy = C.getCanonicalType(argTy).getUnqualifiedType();
-
-      if (T == argTy)
-        return Match;
-      // Check for "compatible types".
-      if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
-        switch (BT->getKind()) {
-          default:
-            break;
-          case BuiltinType::Char_S:
-          case BuiltinType::SChar:
-          case BuiltinType::Char_U:
-          case BuiltinType::UChar:
-            return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match
-                                                                : NoMatch;
-          case BuiltinType::Short:
-            return T == C.UnsignedShortTy ? Match : NoMatch;
-          case BuiltinType::UShort:
-            return T == C.ShortTy ? Match : NoMatch;
-          case BuiltinType::Int:
-            return T == C.UnsignedIntTy ? Match : NoMatch;
-          case BuiltinType::UInt:
-            return T == C.IntTy ? Match : NoMatch;
-          case BuiltinType::Long:
-            return T == C.UnsignedLongTy ? Match : NoMatch;
-          case BuiltinType::ULong:
-            return T == C.LongTy ? Match : NoMatch;
-          case BuiltinType::LongLong:
-            return T == C.UnsignedLongLongTy ? Match : NoMatch;
-          case BuiltinType::ULongLong:
-            return T == C.LongLongTy ? Match : NoMatch;
-        }
-      return NoMatch;
-    }
-
-    case CStrTy: {
-      const PointerType *PT = argTy->getAs<PointerType>();
-      if (!PT)
-        return NoMatch;
-      QualType pointeeTy = PT->getPointeeType();
-      if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
-        switch (BT->getKind()) {
-          case BuiltinType::Void:
-          case BuiltinType::Char_U:
-          case BuiltinType::UChar:
-          case BuiltinType::Char_S:
-          case BuiltinType::SChar:
-            return Match;
-          default:
-            break;
-        }
-
-      return NoMatch;
-    }
-
-    case WCStrTy: {
-      const PointerType *PT = argTy->getAs<PointerType>();
-      if (!PT)
-        return NoMatch;
-      QualType pointeeTy =
-        C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
-      return pointeeTy == C.getWideCharType() ? Match : NoMatch;
-    }
-
-    case WIntTy: {
-      QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType();
-
-      if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)
-        return Match;
-
-      QualType PromoArg = argTy->isPromotableIntegerType()
-                              ? C.getPromotedIntegerType(argTy)
-                              : argTy;
-      PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
-
-      // If the promoted argument is the corresponding signed type of the
-      // wint_t type, then it should match.
-      if (PromoArg->hasSignedIntegerRepresentation() &&
-          C.getCorrespondingUnsignedType(PromoArg) == WInt)
-        return Match;
-
-      return WInt == PromoArg ? Match : NoMatch;
-    }
-
-    case CPointerTy:
-      if (argTy->isVoidPointerType()) {
-        return Match;
-      } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
-            argTy->isBlockPointerType() || argTy->isNullPtrType()) {
-        return NoMatchPedantic;
-      } else {
-        return NoMatch;
-      }
-
-    case ObjCPointerTy: {
-      if (argTy->getAs<ObjCObjectPointerType>() ||
-          argTy->getAs<BlockPointerType>())
-        return Match;
-
-      // Handle implicit toll-free bridging.
-      if (const PointerType *PT = argTy->getAs<PointerType>()) {
-        // Things such as CFTypeRef are really just opaque pointers
-        // to C structs representing CF types that can often be bridged
-        // to Objective-C objects.  Since the compiler doesn't know which
-        // structs can be toll-free bridged, we just accept them all.
-        QualType pointee = PT->getPointeeType();
-        if (pointee->getAsStructureType() || pointee->isVoidType())
-          return Match;
-      }
-      return NoMatch;
-    }
-  }
-
-  llvm_unreachable("Invalid ArgType Kind!");
-}
-
-QualType ArgType::getRepresentativeType(ASTContext &C) const {
-  QualType Res;
-  switch (K) {
-    case InvalidTy:
-      llvm_unreachable("No representative type for Invalid ArgType");
-    case UnknownTy:
-      llvm_unreachable("No representative type for Unknown ArgType");
-    case AnyCharTy:
-      Res = C.CharTy;
-      break;
-    case SpecificTy:
-      Res = T;
-      break;
-    case CStrTy:
-      Res = C.getPointerType(C.CharTy);
-      break;
-    case WCStrTy:
-      Res = C.getPointerType(C.getWideCharType());
-      break;
-    case ObjCPointerTy:
-      Res = C.ObjCBuiltinIdTy;
-      break;
-    case CPointerTy:
-      Res = C.VoidPtrTy;
-      break;
-    case WIntTy: {
-      Res = C.getWIntType();
-      break;
-    }
-  }
-
-  if (Ptr)
-    Res = C.getPointerType(Res);
-  return Res;
-}
-
-std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {
-  std::string S = getRepresentativeType(C).getAsString();
-
-  std::string Alias;
-  if (Name) {
-    // Use a specific name for this type, e.g. "size_t".
-    Alias = Name;
-    if (Ptr) {
-      // If ArgType is actually a pointer to T, append an asterisk.
-      Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";
-    }
-    // If Alias is the same as the underlying type, e.g. wchar_t, then drop it.
-    if (S == Alias)
-      Alias.clear();
-  }
-
-  if (!Alias.empty())
-    return std::string("'") + Alias + "' (aka '" + S + "')";
-  return std::string("'") + S + "'";
-}
-
-
-//===----------------------------------------------------------------------===//
-// Methods on OptionalAmount.
-//===----------------------------------------------------------------------===//
-
-ArgType
-analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {
-  return Ctx.IntTy;
-}
-
-//===----------------------------------------------------------------------===//
-// Methods on LengthModifier.
-//===----------------------------------------------------------------------===//
-
-const char *
-analyze_format_string::LengthModifier::toString() const {
-  switch (kind) {
-  case AsChar:
-    return "hh";
-  case AsShort:
-    return "h";
-  case AsLong: // or AsWideChar
-    return "l";
-  case AsLongLong:
-    return "ll";
-  case AsQuad:
-    return "q";
-  case AsIntMax:
-    return "j";
-  case AsSizeT:
-    return "z";
-  case AsPtrDiff:
-    return "t";
-  case AsInt32:
-    return "I32";
-  case AsInt3264:
-    return "I";
-  case AsInt64:
-    return "I64";
-  case AsLongDouble:
-    return "L";
-  case AsAllocate:
-    return "a";
-  case AsMAllocate:
-    return "m";
-  case AsWide:
-    return "w";
-  case None:
-    return "";
-  }
-  return nullptr;
-}
-
-//===----------------------------------------------------------------------===//
-// Methods on ConversionSpecifier.
-//===----------------------------------------------------------------------===//
-
-const char *ConversionSpecifier::toString() const {
-  switch (kind) {
-  case dArg: return "d";
-  case DArg: return "D";
-  case iArg: return "i";
-  case oArg: return "o";
-  case OArg: return "O";
-  case uArg: return "u";
-  case UArg: return "U";
-  case xArg: return "x";
-  case XArg: return "X";
-  case fArg: return "f";
-  case FArg: return "F";
-  case eArg: return "e";
-  case EArg: return "E";
-  case gArg: return "g";
-  case GArg: return "G";
-  case aArg: return "a";
-  case AArg: return "A";
-  case cArg: return "c";
-  case sArg: return "s";
-  case pArg: return "p";
-  case PArg:
-    return "P";
-  case nArg: return "n";
-  case PercentArg:  return "%";
-  case ScanListArg: return "[";
-  case InvalidSpecifier: return nullptr;
-
-  // POSIX unicode extensions.
-  case CArg: return "C";
-  case SArg: return "S";
-
-  // Objective-C specific specifiers.
-  case ObjCObjArg: return "@";
-
-  // FreeBSD kernel specific specifiers.
-  case FreeBSDbArg: return "b";
-  case FreeBSDDArg: return "D";
-  case FreeBSDrArg: return "r";
-  case FreeBSDyArg: return "y";
-
-  // GlibC specific specifiers.
-  case PrintErrno: return "m";
-
-  // MS specific specifiers.
-  case ZArg: return "Z";
-  }
-  return nullptr;
-}
-
-Optional<ConversionSpecifier>
-ConversionSpecifier::getStandardSpecifier() const {
-  ConversionSpecifier::Kind NewKind;
-
-  switch (getKind()) {
-  default:
-    return None;
-  case DArg:
-    NewKind = dArg;
-    break;
-  case UArg:
-    NewKind = uArg;
-    break;
-  case OArg:
-    NewKind = oArg;
-    break;
-  }
-
-  ConversionSpecifier FixedCS(*this);
-  FixedCS.setKind(NewKind);
-  return FixedCS;
-}
-
-//===----------------------------------------------------------------------===//
-// Methods on OptionalAmount.
-//===----------------------------------------------------------------------===//
-
-void OptionalAmount::toString(raw_ostream &os) const {
-  switch (hs) {
-  case Invalid:
-  case NotSpecified:
-    return;
-  case Arg:
-    if (UsesDotPrefix)
-        os << ".";
-    if (usesPositionalArg())
-      os << "*" << getPositionalArgIndex() << "$";
-    else
-      os << "*";
-    break;
-  case Constant:
-    if (UsesDotPrefix)
-        os << ".";
-    os << amt;
-    break;
-  }
-}
-
-bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
-  switch (LM.getKind()) {
-    case LengthModifier::None:
-      return true;
-
-    // Handle most integer flags
-    case LengthModifier::AsShort:
-      if (Target.getTriple().isOSMSVCRT()) {
-        switch (CS.getKind()) {
-          case ConversionSpecifier::cArg:
-          case ConversionSpecifier::CArg:
-          case ConversionSpecifier::sArg:
-          case ConversionSpecifier::SArg:
-          case ConversionSpecifier::ZArg:
-            return true;
-          default:
-            break;
-        }
-      }
-      LLVM_FALLTHROUGH;
-    case LengthModifier::AsChar:
-    case LengthModifier::AsLongLong:
-    case LengthModifier::AsQuad:
-    case LengthModifier::AsIntMax:
-    case LengthModifier::AsSizeT:
-    case LengthModifier::AsPtrDiff:
-      switch (CS.getKind()) {
-        case ConversionSpecifier::dArg:
-        case ConversionSpecifier::DArg:
-        case ConversionSpecifier::iArg:
-        case ConversionSpecifier::oArg:
-        case ConversionSpecifier::OArg:
-        case ConversionSpecifier::uArg:
-        case ConversionSpecifier::UArg:
-        case ConversionSpecifier::xArg:
-        case ConversionSpecifier::XArg:
-        case ConversionSpecifier::nArg:
-          return true;
-        case ConversionSpecifier::FreeBSDrArg:
-        case ConversionSpecifier::FreeBSDyArg:
-          return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS4();
-        default:
-          return false;
-      }
-
-    // Handle 'l' flag
-    case LengthModifier::AsLong: // or AsWideChar
-      switch (CS.getKind()) {
-        case ConversionSpecifier::dArg:
-        case ConversionSpecifier::DArg:
-        case ConversionSpecifier::iArg:
-        case ConversionSpecifier::oArg:
-        case ConversionSpecifier::OArg:
-        case ConversionSpecifier::uArg:
-        case ConversionSpecifier::UArg:
-        case ConversionSpecifier::xArg:
-        case ConversionSpecifier::XArg:
-        case ConversionSpecifier::aArg:
-        case ConversionSpecifier::AArg:
-        case ConversionSpecifier::fArg:
-        case ConversionSpecifier::FArg:
-        case ConversionSpecifier::eArg:
-        case ConversionSpecifier::EArg:
-        case ConversionSpecifier::gArg:
-        case ConversionSpecifier::GArg:
-        case ConversionSpecifier::nArg:
-        case ConversionSpecifier::cArg:
-        case ConversionSpecifier::sArg:
-        case ConversionSpecifier::ScanListArg:
-        case ConversionSpecifier::ZArg:
-          return true;
-        case ConversionSpecifier::FreeBSDrArg:
-        case ConversionSpecifier::FreeBSDyArg:
-          return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS4();
-        default:
-          return false;
-      }
-
-    case LengthModifier::AsLongDouble:
-      switch (CS.getKind()) {
-        case ConversionSpecifier::aArg:
-        case ConversionSpecifier::AArg:
-        case ConversionSpecifier::fArg:
-        case ConversionSpecifier::FArg:
-        case ConversionSpecifier::eArg:
-        case ConversionSpecifier::EArg:
-        case ConversionSpecifier::gArg:
-        case ConversionSpecifier::GArg:
-          return true;
-        // GNU libc extension.
-        case ConversionSpecifier::dArg:
-        case ConversionSpecifier::iArg:
-        case ConversionSpecifier::oArg:
-        case ConversionSpecifier::uArg:
-        case ConversionSpecifier::xArg:
-        case ConversionSpecifier::XArg:
-          return !Target.getTriple().isOSDarwin() &&
-                 !Target.getTriple().isOSWindows();
-        default:
-          return false;
-      }
-
-    case LengthModifier::AsAllocate:
-      switch (CS.getKind()) {
-        case ConversionSpecifier::sArg:
-        case ConversionSpecifier::SArg:
-        case ConversionSpecifier::ScanListArg:
-          return true;
-        default:
-          return false;
-      }
-
-    case LengthModifier::AsMAllocate:
-      switch (CS.getKind()) {
-        case ConversionSpecifier::cArg:
-        case ConversionSpecifier::CArg:
-        case ConversionSpecifier::sArg:
-        case ConversionSpecifier::SArg:
-        case ConversionSpecifier::ScanListArg:
-          return true;
-        default:
-          return false;
-      }
-    case LengthModifier::AsInt32:
-    case LengthModifier::AsInt3264:
-    case LengthModifier::AsInt64:
-      switch (CS.getKind()) {
-        case ConversionSpecifier::dArg:
-        case ConversionSpecifier::iArg:
-        case ConversionSpecifier::oArg:
-        case ConversionSpecifier::uArg:
-        case ConversionSpecifier::xArg:
-        case ConversionSpecifier::XArg:
-          return Target.getTriple().isOSMSVCRT();
-        default:
-          return false;
-      }
-    case LengthModifier::AsWide:
-      switch (CS.getKind()) {
-        case ConversionSpecifier::cArg:
-        case ConversionSpecifier::CArg:
-        case ConversionSpecifier::sArg:
-        case ConversionSpecifier::SArg:
-        case ConversionSpecifier::ZArg:
-          return Target.getTriple().isOSMSVCRT();
-        default:
-          return false;
-      }
-  }
-  llvm_unreachable("Invalid LengthModifier Kind!");
-}
-
-bool FormatSpecifier::hasStandardLengthModifier() const {
-  switch (LM.getKind()) {
-    case LengthModifier::None:
-    case LengthModifier::AsChar:
-    case LengthModifier::AsShort:
-    case LengthModifier::AsLong:
-    case LengthModifier::AsLongLong:
-    case LengthModifier::AsIntMax:
-    case LengthModifier::AsSizeT:
-    case LengthModifier::AsPtrDiff:
-    case LengthModifier::AsLongDouble:
-      return true;
-    case LengthModifier::AsAllocate:
-    case LengthModifier::AsMAllocate:
-    case LengthModifier::AsQuad:
-    case LengthModifier::AsInt32:
-    case LengthModifier::AsInt3264:
-    case LengthModifier::AsInt64:
-    case LengthModifier::AsWide:
-      return false;
-  }
-  llvm_unreachable("Invalid LengthModifier Kind!");
-}
-
-bool FormatSpecifier::hasStandardConversionSpecifier(
-    const LangOptions &LangOpt) const {
-  switch (CS.getKind()) {
-    case ConversionSpecifier::cArg:
-    case ConversionSpecifier::dArg:
-    case ConversionSpecifier::iArg:
-    case ConversionSpecifier::oArg:
-    case ConversionSpecifier::uArg:
-    case ConversionSpecifier::xArg:
-    case ConversionSpecifier::XArg:
-    case ConversionSpecifier::fArg:
-    case ConversionSpecifier::FArg:
-    case ConversionSpecifier::eArg:
-    case ConversionSpecifier::EArg:
-    case ConversionSpecifier::gArg:
-    case ConversionSpecifier::GArg:
-    case ConversionSpecifier::aArg:
-    case ConversionSpecifier::AArg:
-    case ConversionSpecifier::sArg:
-    case ConversionSpecifier::pArg:
-    case ConversionSpecifier::nArg:
-    case ConversionSpecifier::ObjCObjArg:
-    case ConversionSpecifier::ScanListArg:
-    case ConversionSpecifier::PercentArg:
-    case ConversionSpecifier::PArg:
-      return true;
-    case ConversionSpecifier::CArg:
-    case ConversionSpecifier::SArg:
-      return LangOpt.ObjC;
-    case ConversionSpecifier::InvalidSpecifier:
-    case ConversionSpecifier::FreeBSDbArg:
-    case ConversionSpecifier::FreeBSDDArg:
-    case ConversionSpecifier::FreeBSDrArg:
-    case ConversionSpecifier::FreeBSDyArg:
-    case ConversionSpecifier::PrintErrno:
-    case ConversionSpecifier::DArg:
-    case ConversionSpecifier::OArg:
-    case ConversionSpecifier::UArg:
-    case ConversionSpecifier::ZArg:
-      return false;
-  }
-  llvm_unreachable("Invalid ConversionSpecifier Kind!");
-}
-
-bool FormatSpecifier::hasStandardLengthConversionCombination() const {
-  if (LM.getKind() == LengthModifier::AsLongDouble) {
-    switch(CS.getKind()) {
-        case ConversionSpecifier::dArg:
-        case ConversionSpecifier::iArg:
-        case ConversionSpecifier::oArg:
-        case ConversionSpecifier::uArg:
-        case ConversionSpecifier::xArg:
-        case ConversionSpecifier::XArg:
-          return false;
-        default:
-          return true;
-    }
-  }
-  return true;
-}
-
-Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier() const {
-  if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
-    if (LM.getKind() == LengthModifier::AsLongDouble ||
-        LM.getKind() == LengthModifier::AsQuad) {
-      LengthModifier FixedLM(LM);
-      FixedLM.setKind(LengthModifier::AsLongLong);
-      return FixedLM;
-    }
-  }
-
-  return None;
-}
-
-bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
-                                                LengthModifier &LM) {
-  assert(isa<TypedefType>(QT) && "Expected a TypedefType");
-  const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();
-
-  for (;;) {
-    const IdentifierInfo *Identifier = Typedef->getIdentifier();
-    if (Identifier->getName() == "size_t") {
-      LM.setKind(LengthModifier::AsSizeT);
-      return true;
-    } else if (Identifier->getName() == "ssize_t") {
-      // Not C99, but common in Unix.
-      LM.setKind(LengthModifier::AsSizeT);
-      return true;
-    } else if (Identifier->getName() == "intmax_t") {
-      LM.setKind(LengthModifier::AsIntMax);
-      return true;
-    } else if (Identifier->getName() == "uintmax_t") {
-      LM.setKind(LengthModifier::AsIntMax);
-      return true;
-    } else if (Identifier->getName() == "ptrdiff_t") {
-      LM.setKind(LengthModifier::AsPtrDiff);
-      return true;
-    }
-
-    QualType T = Typedef->getUnderlyingType();
-    if (!isa<TypedefType>(T))
-      break;
-
-    Typedef = cast<TypedefType>(T)->getDecl();
-  }
-  return false;
-}

Removed: cfe/trunk/lib/Analysis/FormatStringParsing.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatStringParsing.h?rev=345970&view=auto
==============================================================================
--- cfe/trunk/lib/Analysis/FormatStringParsing.h (original)
+++ cfe/trunk/lib/Analysis/FormatStringParsing.h (removed)
@@ -1,79 +0,0 @@
-#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
-#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Type.h"
-#include "clang/Analysis/Analyses/FormatString.h"
-
-namespace clang {
-
-class LangOptions;
-
-template <typename T>
-class UpdateOnReturn {
-  T &ValueToUpdate;
-  const T &ValueToCopy;
-public:
-  UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
-    : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
-
-  ~UpdateOnReturn() {
-    ValueToUpdate = ValueToCopy;
-  }
-};
-
-namespace analyze_format_string {
-
-OptionalAmount ParseAmount(const char *&Beg, const char *E);
-OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
-                                      unsigned &argIndex);
-
-OptionalAmount ParsePositionAmount(FormatStringHandler &H,
-                                   const char *Start, const char *&Beg,
-                                   const char *E, PositionContext p);
-
-bool ParseFieldWidth(FormatStringHandler &H,
-                     FormatSpecifier &CS,
-                     const char *Start, const char *&Beg, const char *E,
-                     unsigned *argIndex);
-
-bool ParseArgPosition(FormatStringHandler &H,
-                      FormatSpecifier &CS, const char *Start,
-                      const char *&Beg, const char *E);
-
-/// Returns true if a LengthModifier was parsed and installed in the
-/// FormatSpecifier& argument, and false otherwise.
-bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E,
-                         const LangOptions &LO, bool IsScanf = false);
-
-/// Returns true if the invalid specifier in \p SpecifierBegin is a UTF-8
-/// string; check that it won't go further than \p FmtStrEnd and write
-/// up the total size in \p Len.
-bool ParseUTF8InvalidSpecifier(const char *SpecifierBegin,
-                               const char *FmtStrEnd, unsigned &Len);
-
-template <typename T> class SpecifierResult {
-  T FS;
-  const char *Start;
-  bool Stop;
-public:
-  SpecifierResult(bool stop = false)
-  : Start(nullptr), Stop(stop) {}
-  SpecifierResult(const char *start,
-                  const T &fs)
-  : FS(fs), Start(start), Stop(false) {}
-
-  const char *getStart() const { return Start; }
-  bool shouldStop() const { return Stop; }
-  bool hasValue() const { return Start != nullptr; }
-  const T &getValue() const {
-    assert(hasValue());
-    return FS;
-  }
-  const T &getValue() { return FS; }
-};
-
-} // end analyze_format_string namespace
-} // end clang namespace
-
-#endif

Removed: cfe/trunk/lib/Analysis/OSLog.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/OSLog.cpp?rev=345970&view=auto
==============================================================================
--- cfe/trunk/lib/Analysis/OSLog.cpp (original)
+++ cfe/trunk/lib/Analysis/OSLog.cpp (removed)
@@ -1,203 +0,0 @@
-// TODO: header template
-
-#include "clang/Analysis/Analyses/OSLog.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/Analysis/Analyses/FormatString.h"
-#include "clang/Basic/Builtins.h"
-#include "llvm/ADT/SmallBitVector.h"
-
-using namespace clang;
-
-using clang::analyze_os_log::OSLogBufferItem;
-using clang::analyze_os_log::OSLogBufferLayout;
-
-namespace {
-class OSLogFormatStringHandler
-    : public analyze_format_string::FormatStringHandler {
-private:
-  struct ArgData {
-    const Expr *E = nullptr;
-    Optional<OSLogBufferItem::Kind> Kind;
-    Optional<unsigned> Size;
-    Optional<const Expr *> Count;
-    Optional<const Expr *> Precision;
-    Optional<const Expr *> FieldWidth;
-    unsigned char Flags = 0;
-  };
-  SmallVector<ArgData, 4> ArgsData;
-  ArrayRef<const Expr *> Args;
-
-  OSLogBufferItem::Kind
-  getKind(analyze_format_string::ConversionSpecifier::Kind K) {
-    switch (K) {
-    case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
-      return OSLogBufferItem::StringKind;
-    case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"
-      return OSLogBufferItem::WideStringKind;
-    case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
-      return OSLogBufferItem::PointerKind;
-    case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg: // "%@"
-      return OSLogBufferItem::ObjCObjKind;
-    case clang::analyze_format_string::ConversionSpecifier::PrintErrno: // "%m"
-      return OSLogBufferItem::ErrnoKind;
-    default:
-      return OSLogBufferItem::ScalarKind;
-    }
-    }
-  }
-
-public:
-  OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
-    ArgsData.reserve(Args.size());
-  }
-
-  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
-                                     const char *StartSpecifier,
-                                     unsigned SpecifierLen) {
-    if (!FS.consumesDataArgument() &&
-        FS.getConversionSpecifier().getKind() !=
-            clang::analyze_format_string::ConversionSpecifier::PrintErrno)
-      return true;
-
-    ArgsData.emplace_back();
-    unsigned ArgIndex = FS.getArgIndex();
-    if (ArgIndex < Args.size())
-      ArgsData.back().E = Args[ArgIndex];
-
-    // First get the Kind
-    ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
-    if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
-        !ArgsData.back().E) {
-      // missing argument
-      ArgsData.pop_back();
-      return false;
-    }
-
-    switch (FS.getConversionSpecifier().getKind()) {
-    case clang::analyze_format_string::ConversionSpecifier::sArg:   // "%s"
-    case clang::analyze_format_string::ConversionSpecifier::SArg: { // "%S"
-      auto &precision = FS.getPrecision();
-      switch (precision.getHowSpecified()) {
-      case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s"
-        break;
-      case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s"
-        ArgsData.back().Size = precision.getConstantAmount();
-        break;
-      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
-        ArgsData.back().Count = Args[precision.getArgIndex()];
-        break;
-      case clang::analyze_format_string::OptionalAmount::Invalid:
-        return false;
-      }
-      break;
-    }
-    case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
-      auto &precision = FS.getPrecision();
-      switch (precision.getHowSpecified()) {
-      case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P"
-        return false; // length must be supplied with pointer format specifier
-      case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P"
-        ArgsData.back().Size = precision.getConstantAmount();
-        break;
-      case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
-        ArgsData.back().Count = Args[precision.getArgIndex()];
-        break;
-      case clang::analyze_format_string::OptionalAmount::Invalid:
-        return false;
-      }
-      break;
-    }
-    default:
-      if (FS.getPrecision().hasDataArgument()) {
-        ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
-      }
-      break;
-    }
-    if (FS.getFieldWidth().hasDataArgument()) {
-      ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
-    }
-
-    if (FS.isPrivate()) {
-      ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
-    }
-    if (FS.isPublic()) {
-      ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
-    }
-    return true;
-  }
-
-  void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
-    Layout.Items.clear();
-    for (auto &Data : ArgsData) {
-      if (Data.FieldWidth) {
-        CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
-        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,
-                                  Size, 0);
-      }
-      if (Data.Precision) {
-        CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());
-        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,
-                                  Size, 0);
-      }
-      if (Data.Count) {
-        // "%.*P" has an extra "count" that we insert before the argument.
-        CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
-        Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,
-                                  0);
-      }
-      if (Data.Size)
-        Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),
-                                  Data.Flags);
-      if (Data.Kind) {
-        CharUnits Size;
-        if (*Data.Kind == OSLogBufferItem::ErrnoKind)
-          Size = CharUnits::Zero();
-        else
-          Size = Ctx.getTypeSizeInChars(Data.E->getType());
-        Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
-      } else {
-        auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
-        Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size,
-                                  Data.Flags);
-      }
-    }
-  }
-};
-} // end anonymous namespace
-
-bool clang::analyze_os_log::computeOSLogBufferLayout(
-    ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
-  ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());
-
-  const Expr *StringArg;
-  ArrayRef<const Expr *> VarArgs;
-  switch (E->getBuiltinCallee()) {
-  case Builtin::BI__builtin_os_log_format_buffer_size:
-    assert(E->getNumArgs() >= 1 &&
-           "__builtin_os_log_format_buffer_size takes at least 1 argument");
-    StringArg = E->getArg(0);
-    VarArgs = Args.slice(1);
-    break;
-  case Builtin::BI__builtin_os_log_format:
-    assert(E->getNumArgs() >= 2 &&
-           "__builtin_os_log_format takes at least 2 arguments");
-    StringArg = E->getArg(1);
-    VarArgs = Args.slice(2);
-    break;
-  default:
-    llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");
-  }
-
-  const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());
-  assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
-  StringRef Data = Lit->getString();
-  OSLogFormatStringHandler H(VarArgs);
-  ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
-                    Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
-
-  H.computeLayout(Ctx, Layout);
-  return true;
-}

Removed: cfe/trunk/lib/Analysis/PrintfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=345970&view=auto
==============================================================================
--- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp (removed)
@@ -1,1029 +0,0 @@
-//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Handling of format string in printf and friends.  The structure of format
-// strings for fprintf() are described in C99 7.19.6.1.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/Analyses/FormatString.h"
-#include "clang/Analysis/Analyses/OSLog.h"
-#include "FormatStringParsing.h"
-#include "clang/Basic/TargetInfo.h"
-
-using clang::analyze_format_string::ArgType;
-using clang::analyze_format_string::FormatStringHandler;
-using clang::analyze_format_string::LengthModifier;
-using clang::analyze_format_string::OptionalAmount;
-using clang::analyze_format_string::ConversionSpecifier;
-using clang::analyze_printf::PrintfSpecifier;
-
-using namespace clang;
-
-typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
-        PrintfSpecifierResult;
-
-//===----------------------------------------------------------------------===//
-// Methods for parsing format strings.
-//===----------------------------------------------------------------------===//
-
-using analyze_format_string::ParseNonPositionAmount;
-
-static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
-                           const char *Start, const char *&Beg, const char *E,
-                           unsigned *argIndex) {
-  if (argIndex) {
-    FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
-  } else {
-    const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
-                                           analyze_format_string::PrecisionPos);
-    if (Amt.isInvalid())
-      return true;
-    FS.setPrecision(Amt);
-  }
-  return false;
-}
-
-static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
-                           const char *FlagBeg, const char *E, bool Warn) {
-   StringRef Flag(FlagBeg, E - FlagBeg);
-   // Currently there is only one flag.
-   if (Flag == "tt") {
-     FS.setHasObjCTechnicalTerm(FlagBeg);
-     return false;
-   }
-   // Handle either the case of no flag or an invalid flag.
-   if (Warn) {
-     if (Flag == "")
-       H.HandleEmptyObjCModifierFlag(FlagBeg, E  - FlagBeg);
-     else
-       H.HandleInvalidObjCModifierFlag(FlagBeg, E  - FlagBeg);
-   }
-   return true;
-}
-
-static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
-                                                  const char *&Beg,
-                                                  const char *E,
-                                                  unsigned &argIndex,
-                                                  const LangOptions &LO,
-                                                  const TargetInfo &Target,
-                                                  bool Warn,
-                                                  bool isFreeBSDKPrintf) {
-
-  using namespace clang::analyze_format_string;
-  using namespace clang::analyze_printf;
-
-  const char *I = Beg;
-  const char *Start = nullptr;
-  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
-
-  // Look for a '%' character that indicates the start of a format specifier.
-  for ( ; I != E ; ++I) {
-    char c = *I;
-    if (c == '\0') {
-      // Detect spurious null characters, which are likely errors.
-      H.HandleNullChar(I);
-      return true;
-    }
-    if (c == '%') {
-      Start = I++;  // Record the start of the format specifier.
-      break;
-    }
-  }
-
-  // No format specifier found?
-  if (!Start)
-    return false;
-
-  if (I == E) {
-    // No more characters left?
-    if (Warn)
-      H.HandleIncompleteSpecifier(Start, E - Start);
-    return true;
-  }
-
-  PrintfSpecifier FS;
-  if (ParseArgPosition(H, FS, Start, I, E))
-    return true;
-
-  if (I == E) {
-    // No more characters left?
-    if (Warn)
-      H.HandleIncompleteSpecifier(Start, E - Start);
-    return true;
-  }
-
-  if (*I == '{') {
-    ++I;
-    unsigned char PrivacyFlags = 0;
-    StringRef MatchedStr;
-
-    do {
-      StringRef Str(I, E - I);
-      std::string Match = "^[\t\n\v\f\r ]*(private|public)[\t\n\v\f\r ]*(,|})";
-      llvm::Regex R(Match);
-      SmallVector<StringRef, 2> Matches;
-
-      if (R.match(Str, &Matches)) {
-        MatchedStr = Matches[1];
-        I += Matches[0].size();
-
-        // Set the privacy flag if the privacy annotation in the
-        // comma-delimited segment is at least as strict as the privacy
-        // annotations in previous comma-delimited segments.
-        if (MatchedStr.equals("private"))
-          PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;
-        else if (PrivacyFlags == 0 && MatchedStr.equals("public"))
-          PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
-      } else {
-        size_t CommaOrBracePos =
-            Str.find_if([](char c) { return c == ',' || c == '}'; });
-
-        if (CommaOrBracePos == StringRef::npos) {
-          // Neither a comma nor the closing brace was found.
-          if (Warn)
-            H.HandleIncompleteSpecifier(Start, E - Start);
-          return true;
-        }
-
-        I += CommaOrBracePos + 1;
-      }
-      // Continue until the closing brace is found.
-    } while (*(I - 1) == ',');
-
-    // Set the privacy flag.
-    switch (PrivacyFlags) {
-    case 0:
-      break;
-    case clang::analyze_os_log::OSLogBufferItem::IsPrivate:
-      FS.setIsPrivate(MatchedStr.data());
-      break;
-    case clang::analyze_os_log::OSLogBufferItem::IsPublic:
-      FS.setIsPublic(MatchedStr.data());
-      break;
-    default:
-      llvm_unreachable("Unexpected privacy flag value");
-    }
-  }
-
-  // Look for flags (if any).
-  bool hasMore = true;
-  for ( ; I != E; ++I) {
-    switch (*I) {
-      default: hasMore = false; break;
-      case '\'':
-        // FIXME: POSIX specific.  Always accept?
-        FS.setHasThousandsGrouping(I);
-        break;
-      case '-': FS.setIsLeftJustified(I); break;
-      case '+': FS.setHasPlusPrefix(I); break;
-      case ' ': FS.setHasSpacePrefix(I); break;
-      case '#': FS.setHasAlternativeForm(I); break;
-      case '0': FS.setHasLeadingZeros(I); break;
-    }
-    if (!hasMore)
-      break;
-  }
-
-  if (I == E) {
-    // No more characters left?
-    if (Warn)
-      H.HandleIncompleteSpecifier(Start, E - Start);
-    return true;
-  }
-
-  // Look for the field width (if any).
-  if (ParseFieldWidth(H, FS, Start, I, E,
-                      FS.usesPositionalArg() ? nullptr : &argIndex))
-    return true;
-
-  if (I == E) {
-    // No more characters left?
-    if (Warn)
-      H.HandleIncompleteSpecifier(Start, E - Start);
-    return true;
-  }
-
-  // Look for the precision (if any).
-  if (*I == '.') {
-    ++I;
-    if (I == E) {
-      if (Warn)
-        H.HandleIncompleteSpecifier(Start, E - Start);
-      return true;
-    }
-
-    if (ParsePrecision(H, FS, Start, I, E,
-                       FS.usesPositionalArg() ? nullptr : &argIndex))
-      return true;
-
-    if (I == E) {
-      // No more characters left?
-      if (Warn)
-        H.HandleIncompleteSpecifier(Start, E - Start);
-      return true;
-    }
-  }
-
-  // Look for the length modifier.
-  if (ParseLengthModifier(FS, I, E, LO) && I == E) {
-    // No more characters left?
-    if (Warn)
-      H.HandleIncompleteSpecifier(Start, E - Start);
-    return true;
-  }
-
-  // Look for the Objective-C modifier flags, if any.
-  // We parse these here, even if they don't apply to
-  // the conversion specifier, and then emit an error
-  // later if the conversion specifier isn't '@'.  This
-  // enables better recovery, and we don't know if
-  // these flags are applicable until later.
-  const char *ObjCModifierFlagsStart = nullptr,
-             *ObjCModifierFlagsEnd = nullptr;
-  if (*I == '[') {
-    ObjCModifierFlagsStart = I;
-    ++I;
-    auto flagStart = I;
-    for (;; ++I) {
-      ObjCModifierFlagsEnd = I;
-      if (I == E) {
-        if (Warn)
-          H.HandleIncompleteSpecifier(Start, E - Start);
-        return true;
-      }
-      // Did we find the closing ']'?
-      if (*I == ']') {
-        if (ParseObjCFlags(H, FS, flagStart, I, Warn))
-          return true;
-        ++I;
-        break;
-      }
-      // There are no separators defined yet for multiple
-      // Objective-C modifier flags.  When those are
-      // defined, this is the place to check.
-    }
-  }
-
-  if (*I == '\0') {
-    // Detect spurious null characters, which are likely errors.
-    H.HandleNullChar(I);
-    return true;
-  }
-
-  // Finally, look for the conversion specifier.
-  const char *conversionPosition = I++;
-  ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
-  switch (*conversionPosition) {
-    default:
-      break;
-    // C99: 7.19.6.1 (section 8).
-    case '%': k = ConversionSpecifier::PercentArg;   break;
-    case 'A': k = ConversionSpecifier::AArg; break;
-    case 'E': k = ConversionSpecifier::EArg; break;
-    case 'F': k = ConversionSpecifier::FArg; break;
-    case 'G': k = ConversionSpecifier::GArg; break;
-    case 'X': k = ConversionSpecifier::XArg; break;
-    case 'a': k = ConversionSpecifier::aArg; break;
-    case 'c': k = ConversionSpecifier::cArg; break;
-    case 'd': k = ConversionSpecifier::dArg; break;
-    case 'e': k = ConversionSpecifier::eArg; break;
-    case 'f': k = ConversionSpecifier::fArg; break;
-    case 'g': k = ConversionSpecifier::gArg; break;
-    case 'i': k = ConversionSpecifier::iArg; break;
-    case 'n': k = ConversionSpecifier::nArg; break;
-    case 'o': k = ConversionSpecifier::oArg; break;
-    case 'p': k = ConversionSpecifier::pArg; break;
-    case 's': k = ConversionSpecifier::sArg; break;
-    case 'u': k = ConversionSpecifier::uArg; break;
-    case 'x': k = ConversionSpecifier::xArg; break;
-    // POSIX specific.
-    case 'C': k = ConversionSpecifier::CArg; break;
-    case 'S': k = ConversionSpecifier::SArg; break;
-    // Apple extension for os_log
-    case 'P':
-      k = ConversionSpecifier::PArg;
-      break;
-    // Objective-C.
-    case '@': k = ConversionSpecifier::ObjCObjArg; break;
-    // Glibc specific.
-    case 'm': k = ConversionSpecifier::PrintErrno; break;
-    // FreeBSD kernel specific.
-    case 'b':
-      if (isFreeBSDKPrintf)
-        k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
-      break;
-    case 'r':
-      if (isFreeBSDKPrintf)
-        k = ConversionSpecifier::FreeBSDrArg; // int
-      break;
-    case 'y':
-      if (isFreeBSDKPrintf)
-        k = ConversionSpecifier::FreeBSDyArg; // int
-      break;
-    // Apple-specific.
-    case 'D':
-      if (isFreeBSDKPrintf)
-        k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
-      else if (Target.getTriple().isOSDarwin())
-        k = ConversionSpecifier::DArg;
-      break;
-    case 'O':
-      if (Target.getTriple().isOSDarwin())
-        k = ConversionSpecifier::OArg;
-      break;
-    case 'U':
-      if (Target.getTriple().isOSDarwin())
-        k = ConversionSpecifier::UArg;
-      break;
-    // MS specific.
-    case 'Z':
-      if (Target.getTriple().isOSMSVCRT())
-        k = ConversionSpecifier::ZArg;
-  }
-
-  // Check to see if we used the Objective-C modifier flags with
-  // a conversion specifier other than '@'.
-  if (k != ConversionSpecifier::ObjCObjArg &&
-      k != ConversionSpecifier::InvalidSpecifier &&
-      ObjCModifierFlagsStart) {
-    H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,
-                                           ObjCModifierFlagsEnd + 1,
-                                           conversionPosition);
-    return true;
-  }
-
-  PrintfConversionSpecifier CS(conversionPosition, k);
-  FS.setConversionSpecifier(CS);
-  if (CS.consumesDataArgument() && !FS.usesPositionalArg())
-    FS.setArgIndex(argIndex++);
-  // FreeBSD kernel specific.
-  if (k == ConversionSpecifier::FreeBSDbArg ||
-      k == ConversionSpecifier::FreeBSDDArg)
-    argIndex++;
-
-  if (k == ConversionSpecifier::InvalidSpecifier) {
-    unsigned Len = I - Start;
-    if (ParseUTF8InvalidSpecifier(Start, E, Len)) {
-      CS.setEndScanList(Start + Len);
-      FS.setConversionSpecifier(CS);
-    }
-    // Assume the conversion takes one argument.
-    return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
-  }
-  return PrintfSpecifierResult(Start, FS);
-}
-
-bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
-                                                     const char *I,
-                                                     const char *E,
-                                                     const LangOptions &LO,
-                                                     const TargetInfo &Target,
-                                                     bool isFreeBSDKPrintf) {
-
-  unsigned argIndex = 0;
-
-  // Keep looking for a format specifier until we have exhausted the string.
-  while (I != E) {
-    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
-                                                            LO, Target, true,
-                                                            isFreeBSDKPrintf);
-    // Did a fail-stop error of any kind occur when parsing the specifier?
-    // If so, don't do any more processing.
-    if (FSR.shouldStop())
-      return true;
-    // Did we exhaust the string or encounter an error that
-    // we can recover from?
-    if (!FSR.hasValue())
-      continue;
-    // We have a format specifier.  Pass it to the callback.
-    if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
-                                 I - FSR.getStart()))
-      return true;
-  }
-  assert(I == E && "Format string not exhausted");
-  return false;
-}
-
-bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
-                                                            const char *E,
-                                                            const LangOptions &LO,
-                                                            const TargetInfo &Target) {
-
-  unsigned argIndex = 0;
-
-  // Keep looking for a %s format specifier until we have exhausted the string.
-  FormatStringHandler H;
-  while (I != E) {
-    const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
-                                                            LO, Target, false,
-                                                            false);
-    // Did a fail-stop error of any kind occur when parsing the specifier?
-    // If so, don't do any more processing.
-    if (FSR.shouldStop())
-      return false;
-    // Did we exhaust the string or encounter an error that
-    // we can recover from?
-    if (!FSR.hasValue())
-      continue;
-    const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
-    // Return true if this a %s format specifier.
-    if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)
-      return true;
-  }
-  return false;
-}
-
-//===----------------------------------------------------------------------===//
-// Methods on PrintfSpecifier.
-//===----------------------------------------------------------------------===//
-
-ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
-                                    bool IsObjCLiteral) const {
-  const PrintfConversionSpecifier &CS = getConversionSpecifier();
-
-  if (!CS.consumesDataArgument())
-    return ArgType::Invalid();
-
-  if (CS.getKind() == ConversionSpecifier::cArg)
-    switch (LM.getKind()) {
-      case LengthModifier::None:
-        return Ctx.IntTy;
-      case LengthModifier::AsLong:
-      case LengthModifier::AsWide:
-        return ArgType(ArgType::WIntTy, "wint_t");
-      case LengthModifier::AsShort:
-        if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
-          return Ctx.IntTy;
-        LLVM_FALLTHROUGH;
-      default:
-        return ArgType::Invalid();
-    }
-
-  if (CS.isIntArg())
-    switch (LM.getKind()) {
-      case LengthModifier::AsLongDouble:
-        // GNU extension.
-        return Ctx.LongLongTy;
-      case LengthModifier::None:
-        return Ctx.IntTy;
-      case LengthModifier::AsInt32:
-        return ArgType(Ctx.IntTy, "__int32");
-      case LengthModifier::AsChar: return ArgType::AnyCharTy;
-      case LengthModifier::AsShort: return Ctx.ShortTy;
-      case LengthModifier::AsLong: return Ctx.LongTy;
-      case LengthModifier::AsLongLong:
-      case LengthModifier::AsQuad:
-        return Ctx.LongLongTy;
-      case LengthModifier::AsInt64:
-        return ArgType(Ctx.LongLongTy, "__int64");
-      case LengthModifier::AsIntMax:
-        return ArgType(Ctx.getIntMaxType(), "intmax_t");
-      case LengthModifier::AsSizeT:
-        return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
-      case LengthModifier::AsInt3264:
-        return Ctx.getTargetInfo().getTriple().isArch64Bit()
-                   ? ArgType(Ctx.LongLongTy, "__int64")
-                   : ArgType(Ctx.IntTy, "__int32");
-      case LengthModifier::AsPtrDiff:
-        return ArgType::makePtrdiffT(
-            ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
-      case LengthModifier::AsAllocate:
-      case LengthModifier::AsMAllocate:
-      case LengthModifier::AsWide:
-        return ArgType::Invalid();
-    }
-
-  if (CS.isUIntArg())
-    switch (LM.getKind()) {
-      case LengthModifier::AsLongDouble:
-        // GNU extension.
-        return Ctx.UnsignedLongLongTy;
-      case LengthModifier::None:
-        return Ctx.UnsignedIntTy;
-      case LengthModifier::AsInt32:
-        return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
-      case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
-      case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
-      case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
-      case LengthModifier::AsLongLong:
-      case LengthModifier::AsQuad:
-        return Ctx.UnsignedLongLongTy;
-      case LengthModifier::AsInt64:
-        return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
-      case LengthModifier::AsIntMax:
-        return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
-      case LengthModifier::AsSizeT:
-        return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
-      case LengthModifier::AsInt3264:
-        return Ctx.getTargetInfo().getTriple().isArch64Bit()
-                   ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
-                   : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
-      case LengthModifier::AsPtrDiff:
-        return ArgType::makePtrdiffT(
-            ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
-      case LengthModifier::AsAllocate:
-      case LengthModifier::AsMAllocate:
-      case LengthModifier::AsWide:
-        return ArgType::Invalid();
-    }
-
-  if (CS.isDoubleArg()) {
-    if (LM.getKind() == LengthModifier::AsLongDouble)
-      return Ctx.LongDoubleTy;
-    return Ctx.DoubleTy;
-  }
-
-  if (CS.getKind() == ConversionSpecifier::nArg) {
-    switch (LM.getKind()) {
-      case LengthModifier::None:
-        return ArgType::PtrTo(Ctx.IntTy);
-      case LengthModifier::AsChar:
-        return ArgType::PtrTo(Ctx.SignedCharTy);
-      case LengthModifier::AsShort:
-        return ArgType::PtrTo(Ctx.ShortTy);
-      case LengthModifier::AsLong:
-        return ArgType::PtrTo(Ctx.LongTy);
-      case LengthModifier::AsLongLong:
-      case LengthModifier::AsQuad:
-        return ArgType::PtrTo(Ctx.LongLongTy);
-      case LengthModifier::AsIntMax:
-        return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
-      case LengthModifier::AsSizeT:
-        return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
-      case LengthModifier::AsPtrDiff:
-        return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
-      case LengthModifier::AsLongDouble:
-        return ArgType(); // FIXME: Is this a known extension?
-      case LengthModifier::AsAllocate:
-      case LengthModifier::AsMAllocate:
-      case LengthModifier::AsInt32:
-      case LengthModifier::AsInt3264:
-      case LengthModifier::AsInt64:
-      case LengthModifier::AsWide:
-        return ArgType::Invalid();
-    }
-  }
-
-  switch (CS.getKind()) {
-    case ConversionSpecifier::sArg:
-      if (LM.getKind() == LengthModifier::AsWideChar) {
-        if (IsObjCLiteral)
-          return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
-                         "const unichar *");
-        return ArgType(ArgType::WCStrTy, "wchar_t *");
-      }
-      if (LM.getKind() == LengthModifier::AsWide)
-        return ArgType(ArgType::WCStrTy, "wchar_t *");
-      return ArgType::CStrTy;
-    case ConversionSpecifier::SArg:
-      if (IsObjCLiteral)
-        return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
-                       "const unichar *");
-      if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
-          LM.getKind() == LengthModifier::AsShort)
-        return ArgType::CStrTy;
-      return ArgType(ArgType::WCStrTy, "wchar_t *");
-    case ConversionSpecifier::CArg:
-      if (IsObjCLiteral)
-        return ArgType(Ctx.UnsignedShortTy, "unichar");
-      if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
-          LM.getKind() == LengthModifier::AsShort)
-        return Ctx.IntTy;
-      return ArgType(Ctx.WideCharTy, "wchar_t");
-    case ConversionSpecifier::pArg:
-    case ConversionSpecifier::PArg:
-      return ArgType::CPointerTy;
-    case ConversionSpecifier::ObjCObjArg:
-      return ArgType::ObjCPointerTy;
-    default:
-      break;
-  }
-
-  // FIXME: Handle other cases.
-  return ArgType();
-}
-
-bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
-                              ASTContext &Ctx, bool IsObjCLiteral) {
-  // %n is different from other conversion specifiers; don't try to fix it.
-  if (CS.getKind() == ConversionSpecifier::nArg)
-    return false;
-
-  // Handle Objective-C objects first. Note that while the '%@' specifier will
-  // not warn for structure pointer or void pointer arguments (because that's
-  // how CoreFoundation objects are implemented), we only show a fixit for '%@'
-  // if we know it's an object (block, id, class, or __attribute__((NSObject))).
-  if (QT->isObjCRetainableType()) {
-    if (!IsObjCLiteral)
-      return false;
-
-    CS.setKind(ConversionSpecifier::ObjCObjArg);
-
-    // Disable irrelevant flags
-    HasThousandsGrouping = false;
-    HasPlusPrefix = false;
-    HasSpacePrefix = false;
-    HasAlternativeForm = false;
-    HasLeadingZeroes = false;
-    Precision.setHowSpecified(OptionalAmount::NotSpecified);
-    LM.setKind(LengthModifier::None);
-
-    return true;
-  }
-
-  // Handle strings next (char *, wchar_t *)
-  if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
-    CS.setKind(ConversionSpecifier::sArg);
-
-    // Disable irrelevant flags
-    HasAlternativeForm = 0;
-    HasLeadingZeroes = 0;
-
-    // Set the long length modifier for wide characters
-    if (QT->getPointeeType()->isWideCharType())
-      LM.setKind(LengthModifier::AsWideChar);
-    else
-      LM.setKind(LengthModifier::None);
-
-    return true;
-  }
-
-  // If it's an enum, get its underlying type.
-  if (const EnumType *ETy = QT->getAs<EnumType>())
-    QT = ETy->getDecl()->getIntegerType();
-
-  // We can only work with builtin types.
-  const BuiltinType *BT = QT->getAs<BuiltinType>();
-  if (!BT)
-    return false;
-
-  // Set length modifier
-  switch (BT->getKind()) {
-  case BuiltinType::Bool:
-  case BuiltinType::WChar_U:
-  case BuiltinType::WChar_S:
-  case BuiltinType::Char8: // FIXME: Treat like 'char'?
-  case BuiltinType::Char16:
-  case BuiltinType::Char32:
-  case BuiltinType::UInt128:
-  case BuiltinType::Int128:
-  case BuiltinType::Half:
-  case BuiltinType::Float16:
-  case BuiltinType::Float128:
-  case BuiltinType::ShortAccum:
-  case BuiltinType::Accum:
-  case BuiltinType::LongAccum:
-  case BuiltinType::UShortAccum:
-  case BuiltinType::UAccum:
-  case BuiltinType::ULongAccum:
-  case BuiltinType::ShortFract:
-  case BuiltinType::Fract:
-  case BuiltinType::LongFract:
-  case BuiltinType::UShortFract:
-  case BuiltinType::UFract:
-  case BuiltinType::ULongFract:
-  case BuiltinType::SatShortAccum:
-  case BuiltinType::SatAccum:
-  case BuiltinType::SatLongAccum:
-  case BuiltinType::SatUShortAccum:
-  case BuiltinType::SatUAccum:
-  case BuiltinType::SatULongAccum:
-  case BuiltinType::SatShortFract:
-  case BuiltinType::SatFract:
-  case BuiltinType::SatLongFract:
-  case BuiltinType::SatUShortFract:
-  case BuiltinType::SatUFract:
-  case BuiltinType::SatULongFract:
-    // Various types which are non-trivial to correct.
-    return false;
-
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
-  case BuiltinType::Id:
-#include "clang/Basic/OpenCLImageTypes.def"
-#define SIGNED_TYPE(Id, SingletonId)
-#define UNSIGNED_TYPE(Id, SingletonId)
-#define FLOATING_TYPE(Id, SingletonId)
-#define BUILTIN_TYPE(Id, SingletonId) \
-  case BuiltinType::Id:
-#include "clang/AST/BuiltinTypes.def"
-    // Misc other stuff which doesn't make sense here.
-    return false;
-
-  case BuiltinType::UInt:
-  case BuiltinType::Int:
-  case BuiltinType::Float:
-  case BuiltinType::Double:
-    LM.setKind(LengthModifier::None);
-    break;
-
-  case BuiltinType::Char_U:
-  case BuiltinType::UChar:
-  case BuiltinType::Char_S:
-  case BuiltinType::SChar:
-    LM.setKind(LengthModifier::AsChar);
-    break;
-
-  case BuiltinType::Short:
-  case BuiltinType::UShort:
-    LM.setKind(LengthModifier::AsShort);
-    break;
-
-  case BuiltinType::Long:
-  case BuiltinType::ULong:
-    LM.setKind(LengthModifier::AsLong);
-    break;
-
-  case BuiltinType::LongLong:
-  case BuiltinType::ULongLong:
-    LM.setKind(LengthModifier::AsLongLong);
-    break;
-
-  case BuiltinType::LongDouble:
-    LM.setKind(LengthModifier::AsLongDouble);
-    break;
-  }
-
-  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
-  if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
-    namedTypeToLengthModifier(QT, LM);
-
-  // If fixing the length modifier was enough, we might be done.
-  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
-    // If we're going to offer a fix anyway, make sure the sign matches.
-    switch (CS.getKind()) {
-    case ConversionSpecifier::uArg:
-    case ConversionSpecifier::UArg:
-      if (QT->isSignedIntegerType())
-        CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
-      break;
-    case ConversionSpecifier::dArg:
-    case ConversionSpecifier::DArg:
-    case ConversionSpecifier::iArg:
-      if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
-        CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
-      break;
-    default:
-      // Other specifiers do not have signed/unsigned variants.
-      break;
-    }
-
-    const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
-    if (ATR.isValid() && ATR.matchesType(Ctx, QT))
-      return true;
-  }
-
-  // Set conversion specifier and disable any flags which do not apply to it.
-  // Let typedefs to char fall through to int, as %c is silly for uint8_t.
-  if (!isa<TypedefType>(QT) && QT->isCharType()) {
-    CS.setKind(ConversionSpecifier::cArg);
-    LM.setKind(LengthModifier::None);
-    Precision.setHowSpecified(OptionalAmount::NotSpecified);
-    HasAlternativeForm = 0;
-    HasLeadingZeroes = 0;
-    HasPlusPrefix = 0;
-  }
-  // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
-  else if (QT->isRealFloatingType()) {
-    CS.setKind(ConversionSpecifier::fArg);
-  }
-  else if (QT->isSignedIntegerType()) {
-    CS.setKind(ConversionSpecifier::dArg);
-    HasAlternativeForm = 0;
-  }
-  else if (QT->isUnsignedIntegerType()) {
-    CS.setKind(ConversionSpecifier::uArg);
-    HasAlternativeForm = 0;
-    HasPlusPrefix = 0;
-  } else {
-    llvm_unreachable("Unexpected type");
-  }
-
-  return true;
-}
-
-void PrintfSpecifier::toString(raw_ostream &os) const {
-  // Whilst some features have no defined order, we are using the order
-  // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
-  os << "%";
-
-  // Positional args
-  if (usesPositionalArg()) {
-    os << getPositionalArgIndex() << "$";
-  }
-
-  // Conversion flags
-  if (IsLeftJustified)    os << "-";
-  if (HasPlusPrefix)      os << "+";
-  if (HasSpacePrefix)     os << " ";
-  if (HasAlternativeForm) os << "#";
-  if (HasLeadingZeroes)   os << "0";
-
-  // Minimum field width
-  FieldWidth.toString(os);
-  // Precision
-  Precision.toString(os);
-  // Length modifier
-  os << LM.toString();
-  // Conversion specifier
-  os << CS.toString();
-}
-
-bool PrintfSpecifier::hasValidPlusPrefix() const {
-  if (!HasPlusPrefix)
-    return true;
-
-  // The plus prefix only makes sense for signed conversions
-  switch (CS.getKind()) {
-  case ConversionSpecifier::dArg:
-  case ConversionSpecifier::DArg:
-  case ConversionSpecifier::iArg:
-  case ConversionSpecifier::fArg:
-  case ConversionSpecifier::FArg:
-  case ConversionSpecifier::eArg:
-  case ConversionSpecifier::EArg:
-  case ConversionSpecifier::gArg:
-  case ConversionSpecifier::GArg:
-  case ConversionSpecifier::aArg:
-  case ConversionSpecifier::AArg:
-  case ConversionSpecifier::FreeBSDrArg:
-  case ConversionSpecifier::FreeBSDyArg:
-    return true;
-
-  default:
-    return false;
-  }
-}
-
-bool PrintfSpecifier::hasValidAlternativeForm() const {
-  if (!HasAlternativeForm)
-    return true;
-
-  // Alternate form flag only valid with the oxXaAeEfFgG conversions
-  switch (CS.getKind()) {
-  case ConversionSpecifier::oArg:
-  case ConversionSpecifier::OArg:
-  case ConversionSpecifier::xArg:
-  case ConversionSpecifier::XArg:
-  case ConversionSpecifier::aArg:
-  case ConversionSpecifier::AArg:
-  case ConversionSpecifier::eArg:
-  case ConversionSpecifier::EArg:
-  case ConversionSpecifier::fArg:
-  case ConversionSpecifier::FArg:
-  case ConversionSpecifier::gArg:
-  case ConversionSpecifier::GArg:
-  case ConversionSpecifier::FreeBSDrArg:
-  case ConversionSpecifier::FreeBSDyArg:
-    return true;
-
-  default:
-    return false;
-  }
-}
-
-bool PrintfSpecifier::hasValidLeadingZeros() const {
-  if (!HasLeadingZeroes)
-    return true;
-
-  // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
-  switch (CS.getKind()) {
-  case ConversionSpecifier::dArg:
-  case ConversionSpecifier::DArg:
-  case ConversionSpecifier::iArg:
-  case ConversionSpecifier::oArg:
-  case ConversionSpecifier::OArg:
-  case ConversionSpecifier::uArg:
-  case ConversionSpecifier::UArg:
-  case ConversionSpecifier::xArg:
-  case ConversionSpecifier::XArg:
-  case ConversionSpecifier::aArg:
-  case ConversionSpecifier::AArg:
-  case ConversionSpecifier::eArg:
-  case ConversionSpecifier::EArg:
-  case ConversionSpecifier::fArg:
-  case ConversionSpecifier::FArg:
-  case ConversionSpecifier::gArg:
-  case ConversionSpecifier::GArg:
-  case ConversionSpecifier::FreeBSDrArg:
-  case ConversionSpecifier::FreeBSDyArg:
-    return true;
-
-  default:
-    return false;
-  }
-}
-
-bool PrintfSpecifier::hasValidSpacePrefix() const {
-  if (!HasSpacePrefix)
-    return true;
-
-  // The space prefix only makes sense for signed conversions
-  switch (CS.getKind()) {
-  case ConversionSpecifier::dArg:
-  case ConversionSpecifier::DArg:
-  case ConversionSpecifier::iArg:
-  case ConversionSpecifier::fArg:
-  case ConversionSpecifier::FArg:
-  case ConversionSpecifier::eArg:
-  case ConversionSpecifier::EArg:
-  case ConversionSpecifier::gArg:
-  case ConversionSpecifier::GArg:
-  case ConversionSpecifier::aArg:
-  case ConversionSpecifier::AArg:
-  case ConversionSpecifier::FreeBSDrArg:
-  case ConversionSpecifier::FreeBSDyArg:
-    return true;
-
-  default:
-    return false;
-  }
-}
-
-bool PrintfSpecifier::hasValidLeftJustified() const {
-  if (!IsLeftJustified)
-    return true;
-
-  // The left justified flag is valid for all conversions except n
-  switch (CS.getKind()) {
-  case ConversionSpecifier::nArg:
-    return false;
-
-  default:
-    return true;
-  }
-}
-
-bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
-  if (!HasThousandsGrouping)
-    return true;
-
-  switch (CS.getKind()) {
-    case ConversionSpecifier::dArg:
-    case ConversionSpecifier::DArg:
-    case ConversionSpecifier::iArg:
-    case ConversionSpecifier::uArg:
-    case ConversionSpecifier::UArg:
-    case ConversionSpecifier::fArg:
-    case ConversionSpecifier::FArg:
-    case ConversionSpecifier::gArg:
-    case ConversionSpecifier::GArg:
-      return true;
-    default:
-      return false;
-  }
-}
-
-bool PrintfSpecifier::hasValidPrecision() const {
-  if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
-    return true;
-
-  // Precision is only valid with the diouxXaAeEfFgGsP conversions
-  switch (CS.getKind()) {
-  case ConversionSpecifier::dArg:
-  case ConversionSpecifier::DArg:
-  case ConversionSpecifier::iArg:
-  case ConversionSpecifier::oArg:
-  case ConversionSpecifier::OArg:
-  case ConversionSpecifier::uArg:
-  case ConversionSpecifier::UArg:
-  case ConversionSpecifier::xArg:
-  case ConversionSpecifier::XArg:
-  case ConversionSpecifier::aArg:
-  case ConversionSpecifier::AArg:
-  case ConversionSpecifier::eArg:
-  case ConversionSpecifier::EArg:
-  case ConversionSpecifier::fArg:
-  case ConversionSpecifier::FArg:
-  case ConversionSpecifier::gArg:
-  case ConversionSpecifier::GArg:
-  case ConversionSpecifier::sArg:
-  case ConversionSpecifier::FreeBSDrArg:
-  case ConversionSpecifier::FreeBSDyArg:
-  case ConversionSpecifier::PArg:
-    return true;
-
-  default:
-    return false;
-  }
-}
-bool PrintfSpecifier::hasValidFieldWidth() const {
-  if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
-      return true;
-
-  // The field width is valid for all conversions except n
-  switch (CS.getKind()) {
-  case ConversionSpecifier::nArg:
-    return false;
-
-  default:
-    return true;
-  }
-}

Removed: cfe/trunk/lib/Analysis/ScanfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ScanfFormatString.cpp?rev=345970&view=auto
==============================================================================
--- cfe/trunk/lib/Analysis/ScanfFormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/ScanfFormatString.cpp (removed)
@@ -1,563 +0,0 @@
-//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Handling of format string in scanf and friends.  The structure of format
-// strings for fscanf() are described in C99 7.19.6.2.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/Analyses/FormatString.h"
-#include "FormatStringParsing.h"
-#include "clang/Basic/TargetInfo.h"
-
-using clang::analyze_format_string::ArgType;
-using clang::analyze_format_string::FormatStringHandler;
-using clang::analyze_format_string::LengthModifier;
-using clang::analyze_format_string::OptionalAmount;
-using clang::analyze_format_string::ConversionSpecifier;
-using clang::analyze_scanf::ScanfConversionSpecifier;
-using clang::analyze_scanf::ScanfSpecifier;
-using clang::UpdateOnReturn;
-using namespace clang;
-
-typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
-        ScanfSpecifierResult;
-
-static bool ParseScanList(FormatStringHandler &H,
-                          ScanfConversionSpecifier &CS,
-                          const char *&Beg, const char *E) {
-  const char *I = Beg;
-  const char *start = I - 1;
-  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
-
-  // No more characters?
-  if (I == E) {
-    H.HandleIncompleteScanList(start, I);
-    return true;
-  }
-
-  // Special case: ']' is the first character.
-  if (*I == ']') {
-    if (++I == E) {
-      H.HandleIncompleteScanList(start, I - 1);
-      return true;
-    }
-  }
-
-  // Special case: "^]" are the first characters.
-  if (I + 1 != E && I[0] == '^' && I[1] == ']') {
-    I += 2;
-    if (I == E) {
-      H.HandleIncompleteScanList(start, I - 1);
-      return true;
-    }
-  }
-
-  // Look for a ']' character which denotes the end of the scan list.
-  while (*I != ']') {
-    if (++I == E) {
-      H.HandleIncompleteScanList(start, I - 1);
-      return true;
-    }
-  }
-
-  CS.setEndScanList(I);
-  return false;
-}
-
-// FIXME: Much of this is copy-paste from ParsePrintfSpecifier.
-// We can possibly refactor.
-static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
-                                                const char *&Beg,
-                                                const char *E,
-                                                unsigned &argIndex,
-                                                const LangOptions &LO,
-                                                const TargetInfo &Target) {
-  using namespace clang::analyze_format_string;
-  using namespace clang::analyze_scanf;
-  const char *I = Beg;
-  const char *Start = nullptr;
-  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
-
-    // Look for a '%' character that indicates the start of a format specifier.
-  for ( ; I != E ; ++I) {
-    char c = *I;
-    if (c == '\0') {
-        // Detect spurious null characters, which are likely errors.
-      H.HandleNullChar(I);
-      return true;
-    }
-    if (c == '%') {
-      Start = I++;  // Record the start of the format specifier.
-      break;
-    }
-  }
-
-    // No format specifier found?
-  if (!Start)
-    return false;
-
-  if (I == E) {
-      // No more characters left?
-    H.HandleIncompleteSpecifier(Start, E - Start);
-    return true;
-  }
-
-  ScanfSpecifier FS;
-  if (ParseArgPosition(H, FS, Start, I, E))
-    return true;
-
-  if (I == E) {
-      // No more characters left?
-    H.HandleIncompleteSpecifier(Start, E - Start);
-    return true;
-  }
-
-  // Look for '*' flag if it is present.
-  if (*I == '*') {
-    FS.setSuppressAssignment(I);
-    if (++I == E) {
-      H.HandleIncompleteSpecifier(Start, E - Start);
-      return true;
-    }
-  }
-
-  // Look for the field width (if any).  Unlike printf, this is either
-  // a fixed integer or isn't present.
-  const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E);
-  if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
-    assert(Amt.getHowSpecified() == OptionalAmount::Constant);
-    FS.setFieldWidth(Amt);
-
-    if (I == E) {
-      // No more characters left?
-      H.HandleIncompleteSpecifier(Start, E - Start);
-      return true;
-    }
-  }
-
-  // Look for the length modifier.
-  if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) {
-      // No more characters left?
-    H.HandleIncompleteSpecifier(Start, E - Start);
-    return true;
-  }
-
-  // Detect spurious null characters, which are likely errors.
-  if (*I == '\0') {
-    H.HandleNullChar(I);
-    return true;
-  }
-
-  // Finally, look for the conversion specifier.
-  const char *conversionPosition = I++;
-  ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;
-  switch (*conversionPosition) {
-    default:
-      break;
-    case '%': k = ConversionSpecifier::PercentArg;   break;
-    case 'A': k = ConversionSpecifier::AArg; break;
-    case 'E': k = ConversionSpecifier::EArg; break;
-    case 'F': k = ConversionSpecifier::FArg; break;
-    case 'G': k = ConversionSpecifier::GArg; break;
-    case 'X': k = ConversionSpecifier::XArg; break;
-    case 'a': k = ConversionSpecifier::aArg; break;
-    case 'd': k = ConversionSpecifier::dArg; break;
-    case 'e': k = ConversionSpecifier::eArg; break;
-    case 'f': k = ConversionSpecifier::fArg; break;
-    case 'g': k = ConversionSpecifier::gArg; break;
-    case 'i': k = ConversionSpecifier::iArg; break;
-    case 'n': k = ConversionSpecifier::nArg; break;
-    case 'c': k = ConversionSpecifier::cArg; break;
-    case 'C': k = ConversionSpecifier::CArg; break;
-    case 'S': k = ConversionSpecifier::SArg; break;
-    case '[': k = ConversionSpecifier::ScanListArg; break;
-    case 'u': k = ConversionSpecifier::uArg; break;
-    case 'x': k = ConversionSpecifier::xArg; break;
-    case 'o': k = ConversionSpecifier::oArg; break;
-    case 's': k = ConversionSpecifier::sArg; break;
-    case 'p': k = ConversionSpecifier::pArg; break;
-    // Apple extensions
-      // Apple-specific
-    case 'D':
-      if (Target.getTriple().isOSDarwin())
-        k = ConversionSpecifier::DArg;
-      break;
-    case 'O':
-      if (Target.getTriple().isOSDarwin())
-        k = ConversionSpecifier::OArg;
-      break;
-    case 'U':
-      if (Target.getTriple().isOSDarwin())
-        k = ConversionSpecifier::UArg;
-      break;
-  }
-  ScanfConversionSpecifier CS(conversionPosition, k);
-  if (k == ScanfConversionSpecifier::ScanListArg) {
-    if (ParseScanList(H, CS, I, E))
-      return true;
-  }
-  FS.setConversionSpecifier(CS);
-  if (CS.consumesDataArgument() && !FS.getSuppressAssignment()
-      && !FS.usesPositionalArg())
-    FS.setArgIndex(argIndex++);
-
-  // FIXME: '%' and '*' doesn't make sense.  Issue a warning.
-  // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.
-
-  if (k == ScanfConversionSpecifier::InvalidSpecifier) {
-    unsigned Len = I - Beg;
-    if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {
-      CS.setEndScanList(Beg + Len);
-      FS.setConversionSpecifier(CS);
-    }
-    // Assume the conversion takes one argument.
-    return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);
-  }
-  return ScanfSpecifierResult(Start, FS);
-}
-
-ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
-  const ScanfConversionSpecifier &CS = getConversionSpecifier();
-
-  if (!CS.consumesDataArgument())
-    return ArgType::Invalid();
-
-  switch(CS.getKind()) {
-    // Signed int.
-    case ConversionSpecifier::dArg:
-    case ConversionSpecifier::DArg:
-    case ConversionSpecifier::iArg:
-      switch (LM.getKind()) {
-        case LengthModifier::None:
-          return ArgType::PtrTo(Ctx.IntTy);
-        case LengthModifier::AsChar:
-          return ArgType::PtrTo(ArgType::AnyCharTy);
-        case LengthModifier::AsShort:
-          return ArgType::PtrTo(Ctx.ShortTy);
-        case LengthModifier::AsLong:
-          return ArgType::PtrTo(Ctx.LongTy);
-        case LengthModifier::AsLongLong:
-        case LengthModifier::AsQuad:
-          return ArgType::PtrTo(Ctx.LongLongTy);
-        case LengthModifier::AsInt64:
-          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
-        case LengthModifier::AsIntMax:
-          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
-        case LengthModifier::AsSizeT:
-          return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
-        case LengthModifier::AsPtrDiff:
-          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
-        case LengthModifier::AsLongDouble:
-          // GNU extension.
-          return ArgType::PtrTo(Ctx.LongLongTy);
-        case LengthModifier::AsAllocate:
-        case LengthModifier::AsMAllocate:
-        case LengthModifier::AsInt32:
-        case LengthModifier::AsInt3264:
-        case LengthModifier::AsWide:
-          return ArgType::Invalid();
-      }
-
-    // Unsigned int.
-    case ConversionSpecifier::oArg:
-    case ConversionSpecifier::OArg:
-    case ConversionSpecifier::uArg:
-    case ConversionSpecifier::UArg:
-    case ConversionSpecifier::xArg:
-    case ConversionSpecifier::XArg:
-      switch (LM.getKind()) {
-        case LengthModifier::None:
-          return ArgType::PtrTo(Ctx.UnsignedIntTy);
-        case LengthModifier::AsChar:
-          return ArgType::PtrTo(Ctx.UnsignedCharTy);
-        case LengthModifier::AsShort:
-          return ArgType::PtrTo(Ctx.UnsignedShortTy);
-        case LengthModifier::AsLong:
-          return ArgType::PtrTo(Ctx.UnsignedLongTy);
-        case LengthModifier::AsLongLong:
-        case LengthModifier::AsQuad:
-          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
-        case LengthModifier::AsInt64:
-          return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"));
-        case LengthModifier::AsIntMax:
-          return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
-        case LengthModifier::AsSizeT:
-          return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
-        case LengthModifier::AsPtrDiff:
-          return ArgType::PtrTo(
-              ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
-        case LengthModifier::AsLongDouble:
-          // GNU extension.
-          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
-        case LengthModifier::AsAllocate:
-        case LengthModifier::AsMAllocate:
-        case LengthModifier::AsInt32:
-        case LengthModifier::AsInt3264:
-        case LengthModifier::AsWide:
-          return ArgType::Invalid();
-      }
-
-    // Float.
-    case ConversionSpecifier::aArg:
-    case ConversionSpecifier::AArg:
-    case ConversionSpecifier::eArg:
-    case ConversionSpecifier::EArg:
-    case ConversionSpecifier::fArg:
-    case ConversionSpecifier::FArg:
-    case ConversionSpecifier::gArg:
-    case ConversionSpecifier::GArg:
-      switch (LM.getKind()) {
-        case LengthModifier::None:
-          return ArgType::PtrTo(Ctx.FloatTy);
-        case LengthModifier::AsLong:
-          return ArgType::PtrTo(Ctx.DoubleTy);
-        case LengthModifier::AsLongDouble:
-          return ArgType::PtrTo(Ctx.LongDoubleTy);
-        default:
-          return ArgType::Invalid();
-      }
-
-    // Char, string and scanlist.
-    case ConversionSpecifier::cArg:
-    case ConversionSpecifier::sArg:
-    case ConversionSpecifier::ScanListArg:
-      switch (LM.getKind()) {
-        case LengthModifier::None:
-          return ArgType::PtrTo(ArgType::AnyCharTy);
-        case LengthModifier::AsLong:
-        case LengthModifier::AsWide:
-          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
-        case LengthModifier::AsAllocate:
-        case LengthModifier::AsMAllocate:
-          return ArgType::PtrTo(ArgType::CStrTy);
-        case LengthModifier::AsShort:
-          if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
-            return ArgType::PtrTo(ArgType::AnyCharTy);
-          LLVM_FALLTHROUGH;
-        default:
-          return ArgType::Invalid();
-      }
-    case ConversionSpecifier::CArg:
-    case ConversionSpecifier::SArg:
-      // FIXME: Mac OS X specific?
-      switch (LM.getKind()) {
-        case LengthModifier::None:
-        case LengthModifier::AsWide:
-          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
-        case LengthModifier::AsAllocate:
-        case LengthModifier::AsMAllocate:
-          return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
-        case LengthModifier::AsShort:
-          if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
-            return ArgType::PtrTo(ArgType::AnyCharTy);
-          LLVM_FALLTHROUGH;
-        default:
-          return ArgType::Invalid();
-      }
-
-    // Pointer.
-    case ConversionSpecifier::pArg:
-      return ArgType::PtrTo(ArgType::CPointerTy);
-
-    // Write-back.
-    case ConversionSpecifier::nArg:
-      switch (LM.getKind()) {
-        case LengthModifier::None:
-          return ArgType::PtrTo(Ctx.IntTy);
-        case LengthModifier::AsChar:
-          return ArgType::PtrTo(Ctx.SignedCharTy);
-        case LengthModifier::AsShort:
-          return ArgType::PtrTo(Ctx.ShortTy);
-        case LengthModifier::AsLong:
-          return ArgType::PtrTo(Ctx.LongTy);
-        case LengthModifier::AsLongLong:
-        case LengthModifier::AsQuad:
-          return ArgType::PtrTo(Ctx.LongLongTy);
-        case LengthModifier::AsInt64:
-          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
-        case LengthModifier::AsIntMax:
-          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
-        case LengthModifier::AsSizeT:
-          return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
-        case LengthModifier::AsPtrDiff:
-          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
-        case LengthModifier::AsLongDouble:
-          return ArgType(); // FIXME: Is this a known extension?
-        case LengthModifier::AsAllocate:
-        case LengthModifier::AsMAllocate:
-        case LengthModifier::AsInt32:
-        case LengthModifier::AsInt3264:
-        case LengthModifier::AsWide:
-          return ArgType::Invalid();
-        }
-
-    default:
-      break;
-  }
-
-  return ArgType();
-}
-
-bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
-                             const LangOptions &LangOpt,
-                             ASTContext &Ctx) {
-
-  // %n is different from other conversion specifiers; don't try to fix it.
-  if (CS.getKind() == ConversionSpecifier::nArg)
-    return false;
-
-  if (!QT->isPointerType())
-    return false;
-
-  QualType PT = QT->getPointeeType();
-
-  // If it's an enum, get its underlying type.
-  if (const EnumType *ETy = PT->getAs<EnumType>()) {
-    // Don't try to fix incomplete enums.
-    if (!ETy->getDecl()->isComplete())
-      return false;
-    PT = ETy->getDecl()->getIntegerType();
-  }
-
-  const BuiltinType *BT = PT->getAs<BuiltinType>();
-  if (!BT)
-    return false;
-
-  // Pointer to a character.
-  if (PT->isAnyCharacterType()) {
-    CS.setKind(ConversionSpecifier::sArg);
-    if (PT->isWideCharType())
-      LM.setKind(LengthModifier::AsWideChar);
-    else
-      LM.setKind(LengthModifier::None);
-
-    // If we know the target array length, we can use it as a field width.
-    if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) {
-      if (CAT->getSizeModifier() == ArrayType::Normal)
-        FieldWidth = OptionalAmount(OptionalAmount::Constant,
-                                    CAT->getSize().getZExtValue() - 1,
-                                    "", 0, false);
-
-    }
-    return true;
-  }
-
-  // Figure out the length modifier.
-  switch (BT->getKind()) {
-    // no modifier
-    case BuiltinType::UInt:
-    case BuiltinType::Int:
-    case BuiltinType::Float:
-      LM.setKind(LengthModifier::None);
-      break;
-
-    // hh
-    case BuiltinType::Char_U:
-    case BuiltinType::UChar:
-    case BuiltinType::Char_S:
-    case BuiltinType::SChar:
-      LM.setKind(LengthModifier::AsChar);
-      break;
-
-    // h
-    case BuiltinType::Short:
-    case BuiltinType::UShort:
-      LM.setKind(LengthModifier::AsShort);
-      break;
-
-    // l
-    case BuiltinType::Long:
-    case BuiltinType::ULong:
-    case BuiltinType::Double:
-      LM.setKind(LengthModifier::AsLong);
-      break;
-
-    // ll
-    case BuiltinType::LongLong:
-    case BuiltinType::ULongLong:
-      LM.setKind(LengthModifier::AsLongLong);
-      break;
-
-    // L
-    case BuiltinType::LongDouble:
-      LM.setKind(LengthModifier::AsLongDouble);
-      break;
-
-    // Don't know.
-    default:
-      return false;
-  }
-
-  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
-  if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
-    namedTypeToLengthModifier(PT, LM);
-
-  // If fixing the length modifier was enough, we are done.
-  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
-    const analyze_scanf::ArgType &AT = getArgType(Ctx);
-    if (AT.isValid() && AT.matchesType(Ctx, QT))
-      return true;
-  }
-
-  // Figure out the conversion specifier.
-  if (PT->isRealFloatingType())
-    CS.setKind(ConversionSpecifier::fArg);
-  else if (PT->isSignedIntegerType())
-    CS.setKind(ConversionSpecifier::dArg);
-  else if (PT->isUnsignedIntegerType())
-    CS.setKind(ConversionSpecifier::uArg);
-  else
-    llvm_unreachable("Unexpected type");
-
-  return true;
-}
-
-void ScanfSpecifier::toString(raw_ostream &os) const {
-  os << "%";
-
-  if (usesPositionalArg())
-    os << getPositionalArgIndex() << "$";
-  if (SuppressAssignment)
-    os << "*";
-
-  FieldWidth.toString(os);
-  os << LM.toString();
-  os << CS.toString();
-}
-
-bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
-                                                    const char *I,
-                                                    const char *E,
-                                                    const LangOptions &LO,
-                                                    const TargetInfo &Target) {
-
-  unsigned argIndex = 0;
-
-  // Keep looking for a format specifier until we have exhausted the string.
-  while (I != E) {
-    const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
-                                                          LO, Target);
-    // Did a fail-stop error of any kind occur when parsing the specifier?
-    // If so, don't do any more processing.
-    if (FSR.shouldStop())
-      return true;
-      // Did we exhaust the string or encounter an error that
-      // we can recover from?
-    if (!FSR.hasValue())
-      continue;
-      // We have a format specifier.  Pass it to the callback.
-    if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
-                                I - FSR.getStart())) {
-      return true;
-    }
-  }
-  assert(I == E && "Format string not exhausted");
-  return false;
-}

Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=345971&r1=345970&r2=345971&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Fri Nov  2 06:14:11 2018
@@ -21,7 +21,7 @@
 #include "TargetInfo.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
-#include "clang/Analysis/Analyses/OSLog.h"
+#include "clang/AST/OSLog.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/CodeGen/CGFunctionInfo.h"
@@ -3606,13 +3606,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(
   case Builtin::BI__builtin_os_log_format:
     return emitBuiltinOSLogFormat(*E);
 
-  case Builtin::BI__builtin_os_log_format_buffer_size: {
-    analyze_os_log::OSLogBufferLayout Layout;
-    analyze_os_log::computeOSLogBufferLayout(CGM.getContext(), E, Layout);
-    return RValue::get(ConstantInt::get(ConvertType(E->getType()),
-                                        Layout.size().getQuantity()));
-  }
-
   case Builtin::BI__xray_customevent: {
     if (!ShouldXRayInstrumentFunction())
       return RValue::getIgnored();

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=345971&r1=345970&r2=345971&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Nov  2 06:14:11 2018
@@ -27,6 +27,7 @@
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/ExprOpenMP.h"
+#include "clang/AST/FormatString.h"
 #include "clang/AST/NSAPI.h"
 #include "clang/AST/NonTrivialTypeVisitor.h"
 #include "clang/AST/OperationKinds.h"
@@ -35,7 +36,6 @@
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/AST/UnresolvedSet.h"
-#include "clang/Analysis/Analyses/FormatString.h"
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/Diagnostic.h"

Modified: cfe/trunk/test/CodeGen/builtins.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtins.c?rev=345971&r1=345970&r2=345971&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/builtins.c (original)
+++ cfe/trunk/test/CodeGen/builtins.c Fri Nov  2 06:14:11 2018
@@ -729,25 +729,28 @@ void test_builtin_os_log_merge_helper1(v
 
 // CHECK-LABEL: define void @test_builtin_os_log_errno
 void test_builtin_os_log_errno() {
-  // CHECK: %[[VLA:.*]] = alloca i8, i64 4, align 16
-  // CHECK: call void @__os_log_helper_16_2_1_0_96(i8* %[[VLA]])
+  // CHECK-NOT: @stacksave
+  // CHECK: %[[BUF:.*]] = alloca [4 x i8], align 1
+  // CHECK: %[[DECAY:.*]] = getelementptr inbounds [4 x i8], [4 x i8]* %[[BUF]], i32 0, i32 0
+  // CHECK: call void @__os_log_helper_1_2_1_0_96(i8* %[[DECAY]])
+  // CHECK-NOT: @stackrestore
 
   char buf[__builtin_os_log_format_buffer_size("%m")];
   __builtin_os_log_format(buf, "%m");
 }
 
-// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_16_2_1_0_96
+// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_1_2_1_0_96
 // CHECK: (i8* %[[BUFFER:.*]])
 
 // CHECK: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8
 // CHECK: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8
 // CHECK: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8
 // CHECK: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0
-// CHECK: store i8 2, i8* %[[SUMMARY]], align 16
+// CHECK: store i8 2, i8* %[[SUMMARY]], align 1
 // CHECK: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1
 // CHECK: store i8 1, i8* %[[NUMARGS]], align 1
 // CHECK: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2
-// CHECK: store i8 96, i8* %[[ARGDESCRIPTOR]], align 2
+// CHECK: store i8 96, i8* %[[ARGDESCRIPTOR]], align 1
 // CHECK: %[[ARGSIZE:.*]] = getelementptr i8, i8* %[[BUF]], i64 3
 // CHECK: store i8 0, i8* %[[ARGSIZE]], align 1
 // CHECK-NEXT: ret void




More information about the cfe-commits mailing list