diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp index e4d84ec670b35359a8bdb8422b67bfd5184e9528..4959854a078b30d093ce282886466d5988ed21b9 100644 --- a/lib/Analysis/FormatString.cpp +++ b/lib/Analysis/FormatString.cpp @@ -612,8 +612,20 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { return true; // Handle most integer flags - case LengthModifier::AsChar: case LengthModifier::AsShort: + if (Target.getTriple().isOSMSVCRT()) { + switch (CS.getKind()) { + case ConversionSpecifier::cArg: + case ConversionSpecifier::CArg: + case ConversionSpecifier::sArg: + case ConversionSpecifier::SArg: + return true; + default: + break; + } + } + // Fall through. + case LengthModifier::AsChar: case LengthModifier::AsLongLong: case LengthModifier::AsQuad: case LengthModifier::AsIntMax: diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 38dc8ae5a0fefb393e56b4ee7a40a852b457bd85..1bb3aac887497eac715ff2134ee8dd3e345bc004 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -266,10 +266,14 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, if (CS.getKind() == ConversionSpecifier::cArg) switch (LM.getKind()) { - case LengthModifier::None: return Ctx.IntTy; + 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; default: return ArgType::Invalid(); } @@ -395,10 +399,16 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, 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: return ArgType::CPointerTy; diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp index 5fb2d7ccedd4a9b93e0b82a936ff668df6647da8..d484d8e828cbaa04d034ffc9dd8b7f8aa81dbd20 100644 --- a/lib/Analysis/ScanfFormatString.cpp +++ b/lib/Analysis/ScanfFormatString.cpp @@ -333,6 +333,9 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: return ArgType::PtrTo(ArgType::CStrTy); + case LengthModifier::AsShort: + if (Ctx.getTargetInfo().getTriple().isOSMSVCRT()) + return ArgType::PtrTo(ArgType::AnyCharTy); default: return ArgType::Invalid(); } @@ -346,6 +349,9 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { 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); default: return ArgType::Invalid(); } diff --git a/test/Sema/format-strings-ms.c b/test/Sema/format-strings-ms.c index 3daa0e4f1d5fbf08f5eaf7610f723a3b9da6e603..4a6f91b5598c7338351c864fe1bfe7c36ea18dfa 100644 --- a/test/Sema/format-strings-ms.c +++ b/test/Sema/format-strings-ms.c @@ -63,4 +63,16 @@ void w_test(wchar_t c, wchar_t *s) { } +void h_test(char c, char* s) { + double bad; + printf("%hc", bad); // expected-warning{{format specifies type 'int' but the argument has type 'double'}} + printf("%hC", bad); // expected-warning{{format specifies type 'int' but the argument has type 'double'}} + printf("%hs", bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double'}} + printf("%hS", bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double'}} + scanf("%hc", &bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double *'}} + scanf("%hC", &bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double *'}} + scanf("%hs", &bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double *'}} + scanf("%hS", &bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double *'}} +} + #endif