summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2014-09-07 03:03:51 +0000
committerHans Wennborg <hans@hanshq.net>2014-09-07 03:03:51 +0000
commitc597b4c5291d6c5017ea24fdbdca664b258b7eb2 (patch)
tree9d4f361e75e437d740333d1094ad7438c90eda4c
parent69abd72e4985185536a600cfd40a20554f7c4951 (diff)
downloadbcm5719-llvm-c597b4c5291d6c5017ea24fdbdca664b258b7eb2.tar.gz
bcm5719-llvm-c597b4c5291d6c5017ea24fdbdca664b258b7eb2.zip
MS format strings: parse the 'Z' printf conversion specifier (PR20808)
llvm-svn: 217326
-rw-r--r--clang/include/clang/Analysis/Analyses/FormatString.h2
-rw-r--r--clang/lib/Analysis/FormatString.cpp9
-rw-r--r--clang/lib/Analysis/PrintfFormatString.cpp6
-rw-r--r--clang/test/Sema/format-strings-ms.c12
4 files changed, 26 insertions, 3 deletions
diff --git a/clang/include/clang/Analysis/Analyses/FormatString.h b/clang/include/clang/Analysis/Analyses/FormatString.h
index 52dcd03b0b9..d75194679c0 100644
--- a/clang/include/clang/Analysis/Analyses/FormatString.h
+++ b/clang/include/clang/Analysis/Analyses/FormatString.h
@@ -155,6 +155,8 @@ public:
// ** Printf-specific **
+ ZArg, // MS extension
+
// Objective-C specific specifiers.
ObjCObjArg, // '@'
ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
diff --git a/clang/lib/Analysis/FormatString.cpp b/clang/lib/Analysis/FormatString.cpp
index 4959854a078..8c663d856f6 100644
--- a/clang/lib/Analysis/FormatString.cpp
+++ b/clang/lib/Analysis/FormatString.cpp
@@ -554,6 +554,9 @@ const char *ConversionSpecifier::toString() const {
// GlibC specific specifiers.
case PrintErrno: return "m";
+
+ // MS specific specifiers.
+ case ZArg: return "Z";
}
return nullptr;
}
@@ -619,6 +622,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
case ConversionSpecifier::CArg:
case ConversionSpecifier::sArg:
case ConversionSpecifier::SArg:
+ case ConversionSpecifier::ZArg:
return true;
default:
break;
@@ -671,6 +675,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
case ConversionSpecifier::cArg:
case ConversionSpecifier::sArg:
case ConversionSpecifier::ScanListArg:
+ case ConversionSpecifier::ZArg:
return true;
default:
return false;
@@ -740,7 +745,8 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
case ConversionSpecifier::cArg:
case ConversionSpecifier::CArg:
case ConversionSpecifier::sArg:
- case ConversionSpecifier::SArg: // FIXME: Or Z.
+ case ConversionSpecifier::SArg:
+ case ConversionSpecifier::ZArg:
return Target.getTriple().isOSMSVCRT();
default:
return false;
@@ -805,6 +811,7 @@ bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt)
case ConversionSpecifier::DArg:
case ConversionSpecifier::OArg:
case ConversionSpecifier::UArg:
+ case ConversionSpecifier::ZArg:
return false;
}
llvm_unreachable("Invalid ConversionSpecifier Kind!");
diff --git a/clang/lib/Analysis/PrintfFormatString.cpp b/clang/lib/Analysis/PrintfFormatString.cpp
index 1bb3aac8874..c6453b66549 100644
--- a/clang/lib/Analysis/PrintfFormatString.cpp
+++ b/clang/lib/Analysis/PrintfFormatString.cpp
@@ -198,7 +198,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
case '@': k = ConversionSpecifier::ObjCObjArg; break;
// Glibc specific.
case 'm': k = ConversionSpecifier::PrintErrno; break;
- // Apple-specific
+ // Apple-specific.
case 'D':
if (Target.getTriple().isOSDarwin())
k = ConversionSpecifier::DArg;
@@ -211,6 +211,10 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
if (Target.getTriple().isOSDarwin())
k = ConversionSpecifier::UArg;
break;
+ // MS specific.
+ case 'Z':
+ if (Target.getTriple().isOSMSVCRT())
+ k = ConversionSpecifier::ZArg;
}
PrintfConversionSpecifier CS(conversionPosition, k);
FS.setConversionSpecifier(CS);
diff --git a/clang/test/Sema/format-strings-ms.c b/clang/test/Sema/format-strings-ms.c
index 4a6f91b5598..42676e7a4e0 100644
--- a/clang/test/Sema/format-strings-ms.c
+++ b/clang/test/Sema/format-strings-ms.c
@@ -8,11 +8,12 @@ typedef unsigned short wchar_t;
#ifdef NON_ISO_WARNING
// Split off this test to reduce the warning noise in the rest of the file.
-void non_iso_warning_test(__int32 i32, __int64 i64, wchar_t c) {
+void non_iso_warning_test(__int32 i32, __int64 i64, wchar_t c, void *p) {
printf("%Id", i32); // expected-warning{{'I' length modifier is not supported by ISO C}}
printf("%I32d", i32); // expected-warning{{'I32' length modifier is not supported by ISO C}}
printf("%I64d", i64); // expected-warning{{'I64' length modifier is not supported by ISO C}}
printf("%wc", c); // expected-warning{{'w' length modifier is not supported by ISO C}}
+ printf("%Z", p); // expected-warning{{'Z' conversion specifier is not supported by ISO C}}
}
#else
@@ -75,4 +76,13 @@ void h_test(char c, char* s) {
scanf("%hS", &bad); // expected-warning{{format specifies type 'char *' but the argument has type 'double *'}}
}
+void z_test(void *p) {
+ printf("%Z", p);
+ printf("%hZ", p);
+ printf("%lZ", p);
+ printf("%wZ", p);
+ printf("%hhZ", p); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 'Z' conversion specifier}}
+ scanf("%Z", p); // expected-warning{{invalid conversion specifier 'Z'}}
+}
+
#endif
OpenPOWER on IntegriCloud