From 3636554b63850ac4411f4f7008b89423a76a7820 Mon Sep 17 00:00:00 2001 From: James Molloy Date: Fri, 4 May 2012 10:55:22 +0000 Subject: [PATCH] Fix handling of wint_t - we can't assume wint_t is purely an integer promotion of wchar_t - they may differ in signedness. Teach ASTContext about WIntType, and have it taken from TargetInfo like WCharType. Should fix test/Sema/format-strings.c for ARM, with the exception of one subtest which will fail if wint_t and wchar_t are the same size and wint_t is signed, wchar_t is unsigned. There'll be a followup commit to fix that. Reviewed by Chandler and Hans at http://llvm.org/reviews/r/8 llvm-svn: 156165 --- clang/include/clang/AST/ASTContext.h | 5 +++++ clang/lib/AST/ASTContext.cpp | 2 ++ clang/lib/Analysis/FormatString.cpp | 20 ++++++++++---------- clang/lib/Sema/SemaChecking.cpp | 3 ++- clang/test/Sema/format-strings.c | 11 ++++------- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 96e41c5d0357..a7d4543a59d8 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -557,6 +557,7 @@ public: CanQualType BoolTy; CanQualType CharTy; CanQualType WCharTy; // [C++ 3.9.1p5], integer type in C99. + CanQualType WIntTy; // [C99 7.24.1], integer type unchanged by default promotions. CanQualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99. CanQualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99. CanQualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty; @@ -929,6 +930,10 @@ public: /// Used when in C++, as a GCC extension. QualType getUnsignedWCharType() const; + /// getWIntType - In C99, this returns a type compatible with the type + /// defined in as defined by the target. + QualType getWIntType() const { return WIntTy; } + /// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17) /// defined in . Pointer - pointer requires this (C99 6.5.6p9). QualType getPointerDiffType() const; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index e4308df65351..d80f5b828fec 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -436,6 +436,8 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { } else // C99 WCharTy = getFromTargetType(Target.getWCharType()); + WIntTy = getFromTargetType(Target.getWIntType()); + if (LangOpts.CPlusPlus) // C++0x 3.9.1p5, extension for C++ InitBuiltinType(Char16Ty, BuiltinType::Char16); else // C99 diff --git a/clang/lib/Analysis/FormatString.cpp b/clang/lib/Analysis/FormatString.cpp index ba45865af875..ab69c069114b 100644 --- a/clang/lib/Analysis/FormatString.cpp +++ b/clang/lib/Analysis/FormatString.cpp @@ -319,20 +319,21 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const { } case WIntTy: { - // Instead of doing a lookup for the definition of 'wint_t' (which - // is defined by the system headers) instead see if wchar_t and - // the argument type promote to the same type. - QualType PromoWChar = - C.getWCharType()->isPromotableIntegerType() - ? C.getPromotedIntegerType(C.getWCharType()) : C.getWCharType(); + QualType PromoArg = argTy->isPromotableIntegerType() ? C.getPromotedIntegerType(argTy) : argTy; - PromoWChar = C.getCanonicalType(PromoWChar).getUnqualifiedType(); + QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType(); PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType(); - return PromoWChar == PromoArg; + // If the promoted argument is the corresponding signed type of the + // wint_t type, then it should match. + if (PromoArg->hasSignedIntegerRepresentation() && + C.getCorrespondingUnsignedType(PromoArg) == WInt) + return true; + + return WInt == PromoArg; } case CPointerTy: @@ -380,8 +381,7 @@ QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const { case CPointerTy: return C.VoidPtrTy; case WIntTy: { - QualType WC = C.getWCharType(); - return WC->isPromotableIntegerType() ? C.getPromotedIntegerType(WC) : WC; + return C.getWIntType(); } } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index dad082748827..0c8309e58e5d 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2392,7 +2392,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier // or 'short' to an 'int'. This is done because printf is a varargs // function. if (const ImplicitCastExpr *ICE = dyn_cast(Ex)) - if (ICE->getType() == S.Context.IntTy) { + if (ICE->getType() == S.Context.IntTy || + ICE->getType() == S.Context.UnsignedIntTy) { // All further checking is done on the subexpression. Ex = ICE->getSubExpr(); if (ATR.matchesType(S.Context, Ex->getType())) diff --git a/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c index 7e968899ac23..d1dca7e2fb02 100644 --- a/clang/test/Sema/format-strings.c +++ b/clang/test/Sema/format-strings.c @@ -1,7 +1,9 @@ // RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs %s +#define __need_wint_t #include -typedef __typeof(sizeof(int)) size_t; +#include // For wint_t and wchar_t + typedef struct _FILE FILE; int fprintf(FILE *, const char *restrict, ...); int printf(const char *restrict, ...); // expected-note{{passing argument to parameter here}} @@ -258,7 +260,6 @@ void f0(int_t x) { printf("%d\n", x); } // Unicode test cases. These are possibly specific to Mac OS X. If so, they should // eventually be moved into a separate test. -typedef __WCHAR_TYPE__ wchar_t; void test_unicode_conversions(wchar_t *s) { printf("%S", s); // no-warning @@ -332,16 +333,12 @@ void bug7377_bad_length_mod_usage() { } // PR 7981 - handle '%lc' (wint_t) -#ifndef wint_t -typedef int __darwin_wint_t; -typedef __darwin_wint_t wint_t; -#endif void pr7981(wint_t c, wchar_t c2) { printf("%lc", c); // no-warning printf("%lc", 1.0); // expected-warning{{the argument has type 'double'}} printf("%lc", (char) 1); // no-warning - printf("%lc", &c); // expected-warning{{the argument has type 'wint_t *' (aka 'int *')}} + printf("%lc", &c); // expected-warning{{the argument has type 'wint_t *'}} printf("%lc", c2); // no-warning }