Index: include/clang/Analysis/Analyses/FormatString.h =================================================================== --- include/clang/Analysis/Analyses/FormatString.h +++ include/clang/Analysis/Analyses/FormatString.h @@ -73,6 +73,9 @@ 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 @@ -95,6 +98,9 @@ case AsLongLong: case AsChar: return 2; + case AsInt32: + case AsInt64: + return 3; case None: return 0; } Index: lib/Analysis/FormatString.cpp =================================================================== --- lib/Analysis/FormatString.cpp +++ lib/Analysis/FormatString.cpp @@ -223,6 +223,27 @@ 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; } LengthModifier lm(lmPosition, lmKind); FS.setLengthModifier(lm); @@ -471,6 +492,12 @@ return "z"; case AsPtrDiff: return "t"; + case AsInt32: + return "I32"; + case AsInt3264: + return "I"; + case AsInt64: + return "I64"; case AsLongDouble: return "L"; case AsAllocate: @@ -514,7 +541,7 @@ case ScanListArg: return "["; case InvalidSpecifier: return NULL; - // MacOS X unicode extensions. + // POSIX unicode extensions. case CArg: return "C"; case SArg: return "S"; @@ -678,6 +705,20 @@ 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; + } } llvm_unreachable("Invalid LengthModifier Kind!"); } @@ -697,6 +738,9 @@ case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: case LengthModifier::AsQuad: + case LengthModifier::AsInt32: + case LengthModifier::AsInt3264: + case LengthModifier::AsInt64: return false; } llvm_unreachable("Invalid LengthModifier Kind!"); Index: lib/Analysis/PrintfFormatString.cpp =================================================================== --- lib/Analysis/PrintfFormatString.cpp +++ lib/Analysis/PrintfFormatString.cpp @@ -187,8 +187,8 @@ 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 '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. @@ -278,18 +278,26 @@ case LengthModifier::AsLongDouble: // GNU extension. return Ctx.LongLongTy; - case LengthModifier::None: return Ctx.IntTy; + 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: // FIXME: How to get the corresponding signed version of size_t? return ArgType(); + case LengthModifier::AsInt3264: + return Ctx.getTargetInfo().getTriple().isArch64Bit() ? Ctx.LongLongTy + : Ctx.IntTy; case LengthModifier::AsPtrDiff: return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"); case LengthModifier::AsAllocate: @@ -302,17 +310,26 @@ case LengthModifier::AsLongDouble: // GNU extension. return Ctx.UnsignedLongLongTy; - case LengthModifier::None: return Ctx.UnsignedIntTy; + 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(Ctx.getSizeType(), "size_t"); + case LengthModifier::AsInt3264: + return Ctx.getTargetInfo().getTriple().isArch64Bit() + ? Ctx.UnsignedLongLongTy + : Ctx.UnsignedIntTy; case LengthModifier::AsPtrDiff: // FIXME: How to get the corresponding unsigned // version of ptrdiff_t? @@ -351,6 +368,9 @@ return ArgType(); // FIXME: Is this a known extension? case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: + case LengthModifier::AsInt32: + case LengthModifier::AsInt3264: + case LengthModifier::AsInt64: return ArgType::Invalid(); } } Index: lib/Analysis/ScanfFormatString.cpp =================================================================== --- lib/Analysis/ScanfFormatString.cpp +++ lib/Analysis/ScanfFormatString.cpp @@ -232,6 +232,8 @@ 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: @@ -243,8 +245,9 @@ // GNU extension. return ArgType::PtrTo(Ctx.LongLongTy); case LengthModifier::AsAllocate: - return ArgType::Invalid(); case LengthModifier::AsMAllocate: + case LengthModifier::AsInt32: + case LengthModifier::AsInt3264: return ArgType::Invalid(); } @@ -267,6 +270,8 @@ 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: @@ -278,8 +283,9 @@ // GNU extension. return ArgType::PtrTo(Ctx.UnsignedLongLongTy); case LengthModifier::AsAllocate: - return ArgType::Invalid(); case LengthModifier::AsMAllocate: + case LengthModifier::AsInt32: + case LengthModifier::AsInt3264: return ArgType::Invalid(); } @@ -349,6 +355,8 @@ 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: @@ -359,6 +367,8 @@ return ArgType(); // FIXME: Is this a known extension? case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: + case LengthModifier::AsInt32: + case LengthModifier::AsInt3264: return ArgType::Invalid(); } Index: test/Sema/format-strings-ms.c =================================================================== --- /dev/null +++ test/Sema/format-strings-ms.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility -triple=i386-pc-win32 -pedantic %s + +int printf(const char *format, ...) __attribute__((format(printf, 1, 2))); + +void test() { + short val = 30; + printf("val = %I64d\n", val); // expected-warning{{'I64' length modifier is not supported by ISO C}} \ + // expected-warning{{format specifies type '__int64' (aka 'long long') but the argument has type 'short'}} +}