forked from OSchip/llvm-project
Tweak printf format string parsing to accept 'hh' conversion specifier to accept any char, not just signed char. Fixes <rdar://problem/10303638>.
llvm-svn: 142908
This commit is contained in:
parent
baabbb779d
commit
74e82bd190
|
@ -199,7 +199,7 @@ protected:
|
||||||
class ArgTypeResult {
|
class ArgTypeResult {
|
||||||
public:
|
public:
|
||||||
enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
|
enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
|
||||||
CStrTy, WCStrTy, WIntTy };
|
AnyCharTy, CStrTy, WCStrTy, WIntTy };
|
||||||
private:
|
private:
|
||||||
const Kind K;
|
const Kind K;
|
||||||
QualType T;
|
QualType T;
|
||||||
|
|
|
@ -183,13 +183,13 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
|
||||||
return false;
|
return false;
|
||||||
case 'h':
|
case 'h':
|
||||||
++I;
|
++I;
|
||||||
lmKind = (I != E && *I == 'h') ?
|
lmKind = (I != E && *I == 'h') ? (++I, LengthModifier::AsChar)
|
||||||
++I, LengthModifier::AsChar : LengthModifier::AsShort;
|
: LengthModifier::AsShort;
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
++I;
|
++I;
|
||||||
lmKind = (I != E && *I == 'l') ?
|
lmKind = (I != E && *I == 'l') ? (++I, LengthModifier::AsLongLong)
|
||||||
++I, LengthModifier::AsLongLong : LengthModifier::AsLong;
|
: LengthModifier::AsLong;
|
||||||
break;
|
break;
|
||||||
case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;
|
case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;
|
||||||
case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;
|
case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;
|
||||||
|
@ -213,7 +213,21 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
|
||||||
|
|
||||||
case UnknownTy:
|
case UnknownTy:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case AnyCharTy: {
|
||||||
|
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 true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
case SpecificTy: {
|
case SpecificTy: {
|
||||||
argTy = C.getCanonicalType(argTy).getUnqualifiedType();
|
argTy = C.getCanonicalType(argTy).getUnqualifiedType();
|
||||||
if (T == argTy)
|
if (T == argTy)
|
||||||
|
@ -314,6 +328,8 @@ QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
|
||||||
llvm_unreachable("No representative type for Invalid ArgTypeResult");
|
llvm_unreachable("No representative type for Invalid ArgTypeResult");
|
||||||
case UnknownTy:
|
case UnknownTy:
|
||||||
return QualType();
|
return QualType();
|
||||||
|
case AnyCharTy:
|
||||||
|
return C.CharTy;
|
||||||
case SpecificTy:
|
case SpecificTy:
|
||||||
return T;
|
return T;
|
||||||
case CStrTy:
|
case CStrTy:
|
||||||
|
|
|
@ -297,7 +297,7 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
|
||||||
case LengthModifier::AsLongDouble:
|
case LengthModifier::AsLongDouble:
|
||||||
return ArgTypeResult::Invalid();
|
return ArgTypeResult::Invalid();
|
||||||
case LengthModifier::None: return Ctx.IntTy;
|
case LengthModifier::None: return Ctx.IntTy;
|
||||||
case LengthModifier::AsChar: return Ctx.SignedCharTy;
|
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: return Ctx.LongLongTy;
|
||||||
|
|
|
@ -212,6 +212,12 @@ void test12(char *b) {
|
||||||
asprintf(&b, "%d", "asprintf"); // expected-warning{{conversion specifies type 'int' but the argument has type 'char *'}}
|
asprintf(&b, "%d", "asprintf"); // expected-warning{{conversion specifies type 'int' but the argument has type 'char *'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test13(short x) {
|
||||||
|
char bel = 007;
|
||||||
|
printf("bel: '0%hhd'\n", bel); // no-warning
|
||||||
|
printf("x: '0%hhd'\n", x); // expected-warning {{conversion specifies type 'char' but the argument has type 'short'}}
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct __aslclient *aslclient;
|
typedef struct __aslclient *aslclient;
|
||||||
typedef struct __aslmsg *aslmsg;
|
typedef struct __aslmsg *aslmsg;
|
||||||
int asl_log(aslclient asl, aslmsg msg, int level, const char *format, ...) __attribute__((__format__ (__printf__, 4, 5)));
|
int asl_log(aslclient asl, aslmsg msg, int level, const char *format, ...) __attribute__((__format__ (__printf__, 4, 5)));
|
||||||
|
|
Loading…
Reference in New Issue