Index: clang/include/clang/AST/FormatString.h =================================================================== --- clang/include/clang/AST/FormatString.h +++ clang/include/clang/AST/FormatString.h @@ -65,22 +65,24 @@ public: enum Kind { None, - AsChar, // 'hh' - AsShort, // 'h' - AsShortLong, // 'hl' (OpenCL float/int vector element) - AsLong, // 'l' - AsLongLong, // 'll' - AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types) - 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 - AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z + AsChar, // 'hh' + AsShort, // 'h' + AsShortLong, // 'hl' (OpenCL float/int vector element) + AsLong, // 'l' + AsLongLong, // 'll' + AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types) + 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 + AsUTF16, // for '%l16(c|s)', Clang extension + AsUTF32, // for '%l32(c|s)', Clang extension + AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z AsWideChar = AsLong // for '%ls', only makes sense for printf }; Index: clang/lib/AST/FormatString.cpp =================================================================== --- clang/lib/AST/FormatString.cpp +++ clang/lib/AST/FormatString.cpp @@ -520,6 +520,12 @@ case WCStrTy: Res = C.getPointerType(C.getWideCharType()); break; + case Char16Ty: + Res = C.getPointerType(C.getChar16Type()); + break; + case Char32Ty: + Res = C.getPointerType(C.getChar32Type()); + break; case ObjCPointerTy: Res = C.ObjCBuiltinIdTy; break; @@ -607,6 +613,10 @@ return "m"; case AsWide: return "w"; + case AsUTF16: + return "l16"; + case AsUTF32: + return "l32"; case None: return ""; } @@ -860,6 +870,17 @@ default: return false; } + case LengthModifier::AsUTF16: + case LengthModifier::AsUTF32: + switch (CS.getKind()) { + case ConversionSpecifier::cArg: + case ConversionSpecifier::CArg: + case ConversionSpecifier::sArg: + case ConversionSpecifier::SArg: + return true; + default: + return false; + } case LengthModifier::AsWide: switch (CS.getKind()) { case ConversionSpecifier::cArg: @@ -886,6 +907,8 @@ case LengthModifier::AsSizeT: case LengthModifier::AsPtrDiff: case LengthModifier::AsLongDouble: + case LengthModifier::AsUTF16: + case LengthModifier::AsUTF32: return true; case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: @@ -997,6 +1020,12 @@ } else if (Identifier->getName() == "ptrdiff_t") { LM.setKind(LengthModifier::AsPtrDiff); return true; + } else if (Identifier->getName() == "char16_t") { + LM.setKind(LengthModifier::AsUTF16); + return true; + } else if (Identifier->getName() == "char32_t") { + LM.setKind(LengthModifier::AsUTF32); + return true; } QualType T = Typedef->getUnderlyingType(); Index: clang/test/Sema/format-strings-int-typedefs.c =================================================================== --- clang/test/Sema/format-strings-int-typedefs.c +++ clang/test/Sema/format-strings-int-typedefs.c @@ -10,8 +10,17 @@ printf("%td", 42.0); // expected-warning {{format specifies type 'ptrdiff_t' (aka 'int')}} printf("%lc", 42.0); // expected-warning {{format specifies type 'wint_t' (aka 'int')}} printf("%ls", 42.0); // expected-warning {{format specifies type 'wchar_t *' (aka 'int *')}} + printf("%l16c", 42.0); // expected-warning {{format specifies type 'char16_t' (aka 'int')}} + printf("%l16s", 42.0); // expected-warning {{format specifies type 'char16_t *' (aka 'int *')}} + printf("%l32c", 42.0); // expected-warning {{format specifies type 'char32_t' (aka 'int')}} + printf("%l32s", 42.0); // expected-warning {{format specifies type 'char32_t *' (aka 'int *')}} printf("%S", 42.0); // expected-warning {{format specifies type 'wchar_t *' (aka 'int *')}} printf("%C", 42.0); // expected-warning {{format specifies type 'wchar_t' (aka 'int')}} + + wprintf(L"%l16c", 42.0); // expected-warning {{format specifies type 'char16_t' (aka 'short')}} + wprintf(L"%l16s", 42.0); // expected-warning {{format specifies type 'char16_t *' (aka 'short *')}} + wprintf(L"%l32c", 42.0); // expected-warning {{format specifies type 'char32_t' (aka 'int')}} + wprintf(L"%l32s", 42.0); // expected-warning {{format specifies type 'char32_t *' (aka 'int *')}} scanf("%jd", 0); // expected-warning {{format specifies type 'intmax_t *' (aka 'long long *')}} scanf("%ju", 0); // expected-warning {{format specifies type 'uintmax_t *' (aka 'unsigned long long *')}} @@ -19,8 +28,17 @@ scanf("%td", 0); // expected-warning {{format specifies type 'ptrdiff_t *' (aka 'int *')}} scanf("%lc", 0); // expected-warning {{format specifies type 'wchar_t *' (aka 'int *')}} scanf("%ls", 0); // expected-warning {{format specifies type 'wchar_t *' (aka 'int *')}} + scanf("%l16c", 0); // expected-warning {{format specifies type 'char16_t *' (aka 'int *')}} + scanf("%l16s", 0); // expected-warning {{format specifies type 'char16_t *' (aka 'int *')}} + scanf("%l32c", 0); // expected-warning {{format specifies type 'char32_t *' (aka 'int *')}} + scanf("%l32s", 0); // expected-warning {{format specifies type 'char32_t *' (aka 'int *')}} scanf("%S", 0); // expected-warning {{format specifies type 'wchar_t *' (aka 'int *')}} scanf("%C", 0); // expected-warning {{format specifies type 'wchar_t *' (aka 'int *')}} + + wscanf("%l16c", 0); // expected-warning {{format specifies type 'char16_t *' (aka 'int *')}} + wscanf("%l16s", 0); // expected-warning {{format specifies type 'char16_t *' (aka 'int *')}} + wscanf("%l32c", 0); // expected-warning {{format specifies type 'char32_t *' (aka 'int *')}} + wscanf("%l32s", 0); // expected-warning {{format specifies type 'char32_t *' (aka 'int *')}} // typedef size_t et al. to something crazy. Index: clang/test/SemaCXX/format-strings.cpp =================================================================== --- clang/test/SemaCXX/format-strings.cpp +++ clang/test/SemaCXX/format-strings.cpp @@ -24,6 +24,8 @@ void g() { printf("%ls", "foo"); // expected-warning{{format specifies type 'wchar_t *' but the argument has type 'const char *'}} + printf("%l16s", "foo"); // expected-warning{{format specifies type 'char16_t *' but the argument has type 'const char *'}} + printf("%l32s", "foo"); // expected-warning{{format specifies type 'char32_t *' but the argument has type 'const char *'}} } // Test that we properly handle format_idx on C++ members.