PR c++/50012 shows a case where we do not issue a -Wsign-compare warning when we should. I introduced this problem here:
2009-06-25 Ian Lance Taylor <i...@google.com> * call.c (avoid_sign_compare_warnings): New static function. (build_new_op): Call it. * typeck.c (cp_build_binary_op): Don't call warn_sign_compare if TREE_NO_WARNING is set on either operand. This patch fixes the problem by avoiding the overload of the TREE_NO_WARNING bit. Making this change required adjusting TYPE_QUALS and TYPE_QUALS_NO_ADDR_SPACE. These are expressions involving enum values. In C++ these expressions wound up promoted to unsigned int, but the callers, at least the ones which do comparisons, expect signed int. For this patch I added an explicit cast to int to the macros, since that is what the callers expect. Bootstrapped and ran gcc testsuite on x86_64-unknown-linux-gnu for all languages. I bootstrapped with and without --disable-build-poststage1-with-cxx. OK for mainline? Ian gcc/ChangeLog: 2012-01-13 Ian Lance Taylor <i...@google.com> PR c++/50012 * tree.h (TYPE_QUALS): Add cast to int. (TYPE_QUALS_NO_ADDR_SPACE): Likewise. gcc/cp/ChangeLog: 2012-01-13 Ian Lance Taylor <i...@google.com> PR c++/50012 * typeck.c (enum_cast_to_uint): New static function. (cp_build_binary_op): When handling warn_sign_compare, don't test for TREE_NO_WARNING. Do call enum_cast_to_uint. * call.c (avoid_sign_compare_warnings): Remove static function. (build_new_op_1): Don't call avoid_sign_compare_warnings. gcc/testsuite/ChangeLog: 2012-01-13 Ian Lance Taylor <i...@google.com> PR c++/50012 * g++.dg/warn/Wsign-compare-4.C: New.
Index: tree.h =================================================================== --- tree.h (revision 183165) +++ tree.h (working copy) @@ -1,6 +1,6 @@ /* Front-end tree definitions for GNU compiler. Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -2298,16 +2298,16 @@ enum cv_qualifier /* The set of type qualifiers for this type. */ #define TYPE_QUALS(NODE) \ - ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST) \ - | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE) \ - | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT) \ - | (ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (NODE)))) + ((int) ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST) \ + | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE) \ + | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT) \ + | (ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (NODE))))) /* The same as TYPE_QUALS without the address space qualifications. */ #define TYPE_QUALS_NO_ADDR_SPACE(NODE) \ - ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST) \ - | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE) \ - | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)) + ((int) ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST) \ + | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE) \ + | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT))) /* These flags are available for each language front end to use internally. */ #define TYPE_LANG_FLAG_0(NODE) (TYPE_CHECK (NODE)->type_common.lang_flag_0) Index: testsuite/g++.dg/warn/Wsign-compare-4.C =================================================================== --- testsuite/g++.dg/warn/Wsign-compare-4.C (revision 0) +++ testsuite/g++.dg/warn/Wsign-compare-4.C (revision 0) @@ -0,0 +1,12 @@ +//PR c++/50012 +// { dg-options "-Wsign-compare" } + +int foo(unsigned int *a, int b) +{ + return (*a) <= b; // { dg-warning "comparison between signed and unsigned" } +} + +int bar(unsigned int *a, int b) +{ + return *a <= b; // { dg-warning "comparison between signed and unsigned" } +} Index: cp/typeck.c =================================================================== --- cp/typeck.c (revision 183165) +++ cp/typeck.c (working copy) @@ -1,6 +1,7 @@ /* Build expressions with type checking for C++ compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011, 2012 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiem...@cygnus.com) @@ -3599,6 +3600,29 @@ build_x_array_ref (tree arg1, tree arg2, return expr; } +/* Return whether OP is an expression of enum type cast to integer + type. In C++ even unsigned enum types are cast to signed integer + types. We do not want to issue warnings about comparisons between + signed and unsigned types when one of the types is an enum type. + Those warnings are always false positives in practice. */ + +static bool +enum_cast_to_uint (tree op) +{ + if (TREE_CODE (op) == NOP_EXPR + && TREE_TYPE (op) == integer_type_node + && TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0))) == ENUMERAL_TYPE + && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op, 0)))) + return true; + + /* The cast may have been pushed into a COND_EXPR. */ + if (TREE_CODE (op) == COND_EXPR) + return (enum_cast_to_uint (TREE_OPERAND (op, 1)) + || enum_cast_to_uint (TREE_OPERAND (op, 2))); + + return false; +} + /* For the c-common bits. */ tree build_binary_op (location_t location, enum tree_code code, tree op0, tree op1, @@ -4465,13 +4489,15 @@ cp_build_binary_op (location_t location, if ((short_compare || code == MIN_EXPR || code == MAX_EXPR) && warn_sign_compare - && !TREE_NO_WARNING (orig_op0) - && !TREE_NO_WARNING (orig_op1) /* Do not warn until the template is instantiated; we cannot bound the ranges of the arguments until that point. */ && !processing_template_decl && (complain & tf_warning) - && c_inhibit_evaluation_warnings == 0) + && c_inhibit_evaluation_warnings == 0 + /* Even unsigned enum types promote to signed int. We don't + want to issue -Wsign-compare warnings for this case. */ + && !enum_cast_to_uint (orig_op0) + && !enum_cast_to_uint (orig_op1)) { warn_for_sign_compare (location, orig_op0, orig_op1, op0, op1, result_type, resultcode); @@ -8525,4 +8551,3 @@ check_literal_operator_args (const_tree return true; } } - Index: cp/call.c =================================================================== --- cp/call.c (revision 183165) +++ cp/call.c (working copy) @@ -1,7 +1,7 @@ /* Functions related to invoking methods and overloaded functions. Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, - 2010, 2011 + 2010, 2011, 2012 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiem...@cygnus.com) and modified by Brendan Kehoe (bren...@cygnus.com). @@ -4880,32 +4880,10 @@ add_candidates (tree fns, tree first_arg } } -/* Even unsigned enum types promote to signed int. We don't want to - issue -Wsign-compare warnings for this case. Here ORIG_ARG is the - original argument and ARG is the argument after any conversions - have been applied. We set TREE_NO_WARNING if we have added a cast - from an unsigned enum type to a signed integer type. */ - -static void -avoid_sign_compare_warnings (tree orig_arg, tree arg) -{ - if (orig_arg != NULL_TREE - && arg != NULL_TREE - && orig_arg != arg - && TREE_CODE (TREE_TYPE (orig_arg)) == ENUMERAL_TYPE - && TYPE_UNSIGNED (TREE_TYPE (orig_arg)) - && INTEGRAL_TYPE_P (TREE_TYPE (arg)) - && !TYPE_UNSIGNED (TREE_TYPE (arg))) - TREE_NO_WARNING (arg) = 1; -} - static tree build_new_op_1 (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3, tree *overload, tsubst_flags_t complain) { - tree orig_arg1 = arg1; - tree orig_arg2 = arg2; - tree orig_arg3 = arg3; struct z_candidate *candidates = 0, *cand; VEC(tree,gc) *arglist; tree fnname; @@ -5200,10 +5178,6 @@ build_new_op_1 (enum tree_code code, int return result; builtin: - avoid_sign_compare_warnings (orig_arg1, arg1); - avoid_sign_compare_warnings (orig_arg2, arg2); - avoid_sign_compare_warnings (orig_arg3, arg3); - switch (code) { case MODIFY_EXPR: