forked from OSchip/llvm-project
Analysis: Add support for MS specific printf format specifiers
Summary: Adds support for %I, %I32 and %I64. Reviewers: hans, jordan_rose, rnk, majnemer Reviewed By: majnemer CC: cfe-commits, cdavis5x Differential Revision: http://llvm-reviews.chandlerc.com/D1456 llvm-svn: 188937
This commit is contained in:
parent
3db39dc1ae
commit
3cba495abc
|
@ -73,6 +73,9 @@ public:
|
|||
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 @@ public:
|
|||
case AsLongLong:
|
||||
case AsChar:
|
||||
return 2;
|
||||
case AsInt32:
|
||||
case AsInt64:
|
||||
return 3;
|
||||
case None:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -223,6 +223,27 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
|
|||
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 @@ analyze_format_string::LengthModifier::toString() const {
|
|||
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 @@ const char *ConversionSpecifier::toString() const {
|
|||
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 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
|
|||
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 @@ bool FormatSpecifier::hasStandardLengthModifier() const {
|
|||
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!");
|
||||
|
|
|
@ -187,8 +187,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
|
|||
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 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
|
|||
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 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
|
|||
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 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -232,6 +232,8 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
|
|||
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 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
|
|||
// 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 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
|
|||
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 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
|
|||
// 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 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
|
|||
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 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
|
|||
return ArgType(); // FIXME: Is this a known extension?
|
||||
case LengthModifier::AsAllocate:
|
||||
case LengthModifier::AsMAllocate:
|
||||
case LengthModifier::AsInt32:
|
||||
case LengthModifier::AsInt3264:
|
||||
return ArgType::Invalid();
|
||||
}
|
||||
|
||||
|
|
|
@ -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'}}
|
||||
}
|
Loading…
Reference in New Issue