Author: aaronballman Date: Tue Dec 18 07:54:38 2018 New Revision: 349497 URL: http://llvm.org/viewvc/llvm-project?rev=349497&view=rev Log: Emit -Wformat properly for bit-field promotions.
Only explicitly look through integer and floating-point promotion where the result type is actually a promotion, which is not always the case for bit-fields in C. Patch by Bevin Hansson. Added: cfe/trunk/test/Sema/format-strings-bitfield-promotion.c cfe/trunk/test/Sema/format-strings-bitfield-promotion.cxx Modified: cfe/trunk/lib/Sema/SemaChecking.cpp Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=349497&r1=349496&r2=349497&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Dec 18 07:54:38 2018 @@ -7771,6 +7771,30 @@ shouldNotPrintDirectly(const ASTContext return std::make_pair(QualType(), StringRef()); } +/// Return true if \p ICE is an implicit argument promotion of an arithmetic +/// type. Bit-field 'promotions' from a higher ranked type to a lower ranked +/// type do not count. +static bool +isArithmeticArgumentPromotion(Sema &S, const ImplicitCastExpr *ICE) { + QualType From = ICE->getSubExpr()->getType(); + QualType To = ICE->getType(); + // It's an integer promotion if the destination type is the promoted + // source type. + if (ICE->getCastKind() == CK_IntegralCast && + From->isPromotableIntegerType() && + S.Context.getPromotedIntegerType(From) == To) + return true; + // Look through vector types, since we do default argument promotion for + // those in OpenCL. + if (const auto *VecTy = From->getAs<ExtVectorType>()) + From = VecTy->getElementType(); + if (const auto *VecTy = To->getAs<ExtVectorType>()) + To = VecTy->getElementType(); + // It's a floating promotion if the source type is a lower rank. + return ICE->getCastKind() == CK_FloatingCast && + S.Context.getFloatingTypeOrder(From, To) < 0; +} + bool CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier, @@ -7798,11 +7822,11 @@ CheckPrintfHandler::checkFormatExpr(cons // Look through argument promotions for our error message's reported type. // This includes the integral and floating promotions, but excludes array - // and function pointer decay; seeing that an argument intended to be a - // string has type 'char [6]' is probably more confusing than 'char *'. + // and function pointer decay (seeing that an argument intended to be a + // string has type 'char [6]' is probably more confusing than 'char *') and + // certain bitfield promotions (bitfields can be 'demoted' to a lesser type). if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { - if (ICE->getCastKind() == CK_IntegralCast || - ICE->getCastKind() == CK_FloatingCast) { + if (isArithmeticArgumentPromotion(S, ICE)) { E = ICE->getSubExpr(); ExprTy = E->getType(); Added: cfe/trunk/test/Sema/format-strings-bitfield-promotion.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings-bitfield-promotion.c?rev=349497&view=auto ============================================================================== --- cfe/trunk/test/Sema/format-strings-bitfield-promotion.c (added) +++ cfe/trunk/test/Sema/format-strings-bitfield-promotion.c Tue Dec 18 07:54:38 2018 @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fsyntax-only -verify %s + +int printf(const char *restrict, ...); + +struct bitfields { + long a : 2; + unsigned long b : 2; + long c : 32; // assumes that int is 32 bits + unsigned long d : 32; // assumes that int is 32 bits +} bf; + +void bitfield_promotion() { + printf("%ld", bf.a); // expected-warning {{format specifies type 'long' but the argument has type 'int'}} + printf("%lu", bf.b); // expected-warning {{format specifies type 'unsigned long' but the argument has type 'int'}} + printf("%ld", bf.c); // expected-warning {{format specifies type 'long' but the argument has type 'int'}} + printf("%lu", bf.d); // expected-warning {{format specifies type 'unsigned long' but the argument has type 'unsigned int'}} +} Added: cfe/trunk/test/Sema/format-strings-bitfield-promotion.cxx URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings-bitfield-promotion.cxx?rev=349497&view=auto ============================================================================== --- cfe/trunk/test/Sema/format-strings-bitfield-promotion.cxx (added) +++ cfe/trunk/test/Sema/format-strings-bitfield-promotion.cxx Tue Dec 18 07:54:38 2018 @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fsyntax-only -verify %s + +// In C++, the bitfield promotion from long to int does not occur, unlike C. +// expected-no-diagnostics + +int printf(const char *restrict, ...); + +struct bitfields { + long a : 2; + unsigned long b : 2; + long c : 32; // assumes that int is 32 bits + unsigned long d : 32; // assumes that int is 32 bits +} bf; + +void bitfield_promotion() { + printf("%ld", bf.a); + printf("%lu", bf.b); + printf("%ld", bf.c); + printf("%lu", bf.d); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits