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
This commit is contained in:
James Molloy 2012-05-04 10:55:22 +00:00
parent 2f5d0191f7
commit 3636554b63
5 changed files with 23 additions and 18 deletions

View File

@ -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 <stddef.h> as defined by the target.
QualType getWIntType() const { return WIntTy; }
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType getPointerDiffType() const;

View File

@ -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

View File

@ -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();
}
}

View File

@ -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<ImplicitCastExpr>(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()))

View File

@ -1,7 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs %s
#define __need_wint_t
#include <stdarg.h>
typedef __typeof(sizeof(int)) size_t;
#include <stddef.h> // 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
}