Format string analysis: give 'q' its own enumerator.
This is in preparation for being able to warn about 'q' and other non-standard format string features. It also allows us to print its name correctly. llvm-svn: 150697
This commit is contained in:
@@ -66,7 +66,8 @@ public:
|
|||||||
AsChar, // 'hh'
|
AsChar, // 'hh'
|
||||||
AsShort, // 'h'
|
AsShort, // 'h'
|
||||||
AsLong, // 'l'
|
AsLong, // 'l'
|
||||||
AsLongLong, // 'll', 'q' (BSD, deprecated)
|
AsLongLong, // 'll'
|
||||||
|
AsQuad, // 'q' (BSD, deprecated, same as 'll')
|
||||||
AsIntMax, // 'j'
|
AsIntMax, // 'j'
|
||||||
AsSizeT, // 'z'
|
AsSizeT, // 'z'
|
||||||
AsPtrDiff, // 't'
|
AsPtrDiff, // 't'
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
|
|||||||
case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;
|
case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;
|
||||||
case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;
|
case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;
|
||||||
case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
|
case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
|
||||||
case 'q': lmKind = LengthModifier::AsLongLong; ++I; break;
|
case 'q': lmKind = LengthModifier::AsQuad; ++I; break;
|
||||||
case 'a':
|
case 'a':
|
||||||
if (IsScanf && !LO.C99 && !LO.CPlusPlus0x) {
|
if (IsScanf && !LO.C99 && !LO.CPlusPlus0x) {
|
||||||
// For scanf in C90, look at the next character to see if this should
|
// For scanf in C90, look at the next character to see if this should
|
||||||
@@ -417,6 +417,8 @@ analyze_format_string::LengthModifier::toString() const {
|
|||||||
return "l";
|
return "l";
|
||||||
case AsLongLong:
|
case AsLongLong:
|
||||||
return "ll";
|
return "ll";
|
||||||
|
case AsQuad:
|
||||||
|
return "q";
|
||||||
case AsIntMax:
|
case AsIntMax:
|
||||||
return "j";
|
return "j";
|
||||||
case AsSizeT:
|
case AsSizeT:
|
||||||
@@ -506,10 +508,11 @@ bool FormatSpecifier::hasValidLengthModifier() const {
|
|||||||
case LengthModifier::None:
|
case LengthModifier::None:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Handle most integer flags
|
// Handle most integer flags
|
||||||
case LengthModifier::AsChar:
|
case LengthModifier::AsChar:
|
||||||
case LengthModifier::AsShort:
|
case LengthModifier::AsShort:
|
||||||
case LengthModifier::AsLongLong:
|
case LengthModifier::AsLongLong:
|
||||||
|
case LengthModifier::AsQuad:
|
||||||
case LengthModifier::AsIntMax:
|
case LengthModifier::AsIntMax:
|
||||||
case LengthModifier::AsSizeT:
|
case LengthModifier::AsSizeT:
|
||||||
case LengthModifier::AsPtrDiff:
|
case LengthModifier::AsPtrDiff:
|
||||||
@@ -526,7 +529,7 @@ bool FormatSpecifier::hasValidLengthModifier() const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle 'l' flag
|
// Handle 'l' flag
|
||||||
case LengthModifier::AsLong:
|
case LengthModifier::AsLong:
|
||||||
switch (CS.getKind()) {
|
switch (CS.getKind()) {
|
||||||
case ConversionSpecifier::dArg:
|
case ConversionSpecifier::dArg:
|
||||||
|
|||||||
@@ -266,7 +266,9 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx,
|
|||||||
case LengthModifier::AsChar: return ArgTypeResult::AnyCharTy;
|
case LengthModifier::AsChar: return ArgTypeResult::AnyCharTy;
|
||||||
case LengthModifier::AsShort: return Ctx.ShortTy;
|
case LengthModifier::AsShort: return Ctx.ShortTy;
|
||||||
case LengthModifier::AsLong: return Ctx.LongTy;
|
case LengthModifier::AsLong: return Ctx.LongTy;
|
||||||
case LengthModifier::AsLongLong: return Ctx.LongLongTy;
|
case LengthModifier::AsLongLong:
|
||||||
|
case LengthModifier::AsQuad:
|
||||||
|
return Ctx.LongLongTy;
|
||||||
case LengthModifier::AsIntMax:
|
case LengthModifier::AsIntMax:
|
||||||
return ArgTypeResult(Ctx.getIntMaxType(), "intmax_t");
|
return ArgTypeResult(Ctx.getIntMaxType(), "intmax_t");
|
||||||
case LengthModifier::AsSizeT:
|
case LengthModifier::AsSizeT:
|
||||||
@@ -288,7 +290,9 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx,
|
|||||||
case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
|
case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
|
||||||
case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
|
case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
|
||||||
case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
|
case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
|
||||||
case LengthModifier::AsLongLong: return Ctx.UnsignedLongLongTy;
|
case LengthModifier::AsLongLong:
|
||||||
|
case LengthModifier::AsQuad:
|
||||||
|
return Ctx.UnsignedLongLongTy;
|
||||||
case LengthModifier::AsIntMax:
|
case LengthModifier::AsIntMax:
|
||||||
return ArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t");
|
return ArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t");
|
||||||
case LengthModifier::AsSizeT:
|
case LengthModifier::AsSizeT:
|
||||||
|
|||||||
@@ -210,7 +210,9 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
|
|||||||
return ArgTypeResult(ArgTypeResult::AnyCharTy);
|
return ArgTypeResult(ArgTypeResult::AnyCharTy);
|
||||||
case LengthModifier::AsShort: return ArgTypeResult(Ctx.ShortTy);
|
case LengthModifier::AsShort: return ArgTypeResult(Ctx.ShortTy);
|
||||||
case LengthModifier::AsLong: return ArgTypeResult(Ctx.LongTy);
|
case LengthModifier::AsLong: return ArgTypeResult(Ctx.LongTy);
|
||||||
case LengthModifier::AsLongLong: return ArgTypeResult(Ctx.LongLongTy);
|
case LengthModifier::AsLongLong:
|
||||||
|
case LengthModifier::AsQuad:
|
||||||
|
return ArgTypeResult(Ctx.LongLongTy);
|
||||||
case LengthModifier::AsIntMax:
|
case LengthModifier::AsIntMax:
|
||||||
return ScanfArgTypeResult(Ctx.getIntMaxType(), "intmax_t *");
|
return ScanfArgTypeResult(Ctx.getIntMaxType(), "intmax_t *");
|
||||||
case LengthModifier::AsSizeT:
|
case LengthModifier::AsSizeT:
|
||||||
@@ -236,6 +238,7 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
|
|||||||
case LengthModifier::AsShort: return ArgTypeResult(Ctx.UnsignedShortTy);
|
case LengthModifier::AsShort: return ArgTypeResult(Ctx.UnsignedShortTy);
|
||||||
case LengthModifier::AsLong: return ArgTypeResult(Ctx.UnsignedLongTy);
|
case LengthModifier::AsLong: return ArgTypeResult(Ctx.UnsignedLongTy);
|
||||||
case LengthModifier::AsLongLong:
|
case LengthModifier::AsLongLong:
|
||||||
|
case LengthModifier::AsQuad:
|
||||||
return ArgTypeResult(Ctx.UnsignedLongLongTy);
|
return ArgTypeResult(Ctx.UnsignedLongLongTy);
|
||||||
case LengthModifier::AsIntMax:
|
case LengthModifier::AsIntMax:
|
||||||
return ScanfArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t *");
|
return ScanfArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t *");
|
||||||
|
|||||||
@@ -117,3 +117,7 @@ void test_longlong(long long *x, unsigned long long *y) {
|
|||||||
scanf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}}
|
scanf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_quad(int *x, long long *llx) {
|
||||||
|
scanf("%qd", x); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}
|
||||||
|
scanf("%qd", llx); // no-warning
|
||||||
|
}
|
||||||
|
|||||||
@@ -167,7 +167,9 @@ void test10(int x, float f, int i, long long lli) {
|
|||||||
printf("%.d", x); // no-warning
|
printf("%.d", x); // no-warning
|
||||||
printf("%.", x); // expected-warning{{incomplete format specifier}}
|
printf("%.", x); // expected-warning{{incomplete format specifier}}
|
||||||
printf("%f", 4); // expected-warning{{format specifies type 'double' but the argument has type 'int'}}
|
printf("%f", 4); // expected-warning{{format specifies type 'double' but the argument has type 'int'}}
|
||||||
printf("%qd", lli);
|
printf("%qd", lli); // no-warning
|
||||||
|
printf("%qd", x); // expected-warning{{format specifies type 'long long' but the argument has type 'int'}}
|
||||||
|
printf("%qp", (void *)0); // expected-warning{{length modifier 'q' results in undefined behavior or no effect with 'p' conversion specifier}}
|
||||||
printf("hhX %hhX", (unsigned char)10); // no-warning
|
printf("hhX %hhX", (unsigned char)10); // no-warning
|
||||||
printf("llX %llX", (long long) 10); // no-warning
|
printf("llX %llX", (long long) 10); // no-warning
|
||||||
// This is fine, because there is an implicit conversion to an int.
|
// This is fine, because there is an implicit conversion to an int.
|
||||||
|
|||||||
Reference in New Issue
Block a user