* [C++ Patch] PR 14710 (add -Wuseless-cast) @ 2012-03-16 21:45 Paolo Carlini 2012-03-17 16:04 ` Jason Merrill 0 siblings, 1 reply; 7+ messages in thread From: Paolo Carlini @ 2012-03-16 21:45 UTC (permalink / raw) To: gcc-patches; +Cc: Jason Merrill [-- Attachment #1: Type: text/plain, Size: 1070 bytes --] Hi, this is what I did to add the warning requested in the PR. Among the slightly less trivial bits: 1- In order not to risk warning *before* an hard error is produced by build_*_cast_1 code, I'm warning only if the cast is actually successful, thus at the end of each build_*_cast function. 2- In order not to warn when the useless cast shows up upon template instantiation I'm using here too the c_inhibit_evaluation_warnings trick (as we do already for warn_sign_compare, I believe). 3- References can be easily missed because wrapped in INDIRECT_REF: as explained at the beginning of tree.c and already used in many places, a REFERENCE_REF_P check (and in case a TREE_OPERAND (expr, 0)) takes care of that. I'm not 100% sure the solution is fully general, though. 4- I'm naming the function implementing the warning itself maybe_warn_about_useless_cast, which seems consistent with the name of at least another warning in typeck.c but other options are possible, of course... Booted and tested x86_64-linux. Thanks, Paolo. ////////////////////// [-- Attachment #2: CL_14710 --] [-- Type: text/plain, Size: 791 bytes --] 2012-03-16 Paolo Carlini <paolo.carlini@oracle.com> PR c++/14710 * doc/invoke.texi: Document -Wuseless-cast. /c-family 2012-03-16 Paolo Carlini <paolo.carlini@oracle.com> PR c++/14710 * c.opt ([Wuseless-cast]): Add. /cp 2012-03-16 Paolo Carlini <paolo.carlini@oracle.com> PR c++/14710 * cp-tree.h (maybe_warn_about_useless_cast): Declare. * typeck.c (maybe_warn_about_useless_cast): Define. (build_reinterpret_cast, build_const_cast, build_static_cast, cp_build_c_cast): Use it. * rtti.c (build_dynamic_cast): Likewise. * pt.c (tsubst_copy_and_build, case CAST_EXPR): Increment/decrement c_inhibit_evaluation_warnings before/after the build_* calls. /testsuite 2012-03-16 Paolo Carlini <paolo.carlini@oracle.com> PR c++/14710 * g++.dg/warn/Wuseless-cast.C: New. [-- Attachment #3: patch_14710 --] [-- Type: text/plain, Size: 10395 bytes --] Index: doc/invoke.texi =================================================================== --- doc/invoke.texi (revision 185462) +++ doc/invoke.texi (working copy) @@ -274,8 +274,8 @@ Objective-C and Objective-C++ Dialects}. -Wunused-label -Wunused-local-typedefs -Wunused-parameter @gol -Wno-unused-result -Wunused-value @gol -Wunused-variable @gol -Wunused-but-set-parameter -Wunused-but-set-variable @gol --Wvariadic-macros -Wvector-operation-performance -Wvla --Wvolatile-register-var -Wwrite-strings -Wzero-as-null-pointer-constant} +-Wuseless-cast -Wvariadic-macros -Wvector-operation-performance @gol +-Wvla -Wvolatile-register-var -Wwrite-strings -Wzero-as-null-pointer-constant} @item C and Objective-C-only Warning Options @gccoptlist{-Wbad-function-cast -Wmissing-declarations @gol @@ -4199,6 +4199,11 @@ types. @option{-Wconversion-null} is enabled by de Warn when a literal '0' is used as null pointer constant. This can be useful to facilitate the conversion to @code{nullptr} in C++11. +@item -Wuseless-cast @r{(C++ and Objective-C++ only)} +@opindex Wuseless-cast +@opindex Wno-useless-cast +Warn when an expression is casted to its own type. + @item -Wempty-body @opindex Wempty-body @opindex Wno-empty-body Index: c-family/c.opt =================================================================== --- c-family/c.opt (revision 185462) +++ c-family/c.opt (working copy) @@ -697,6 +697,10 @@ Wzero-as-null-pointer-constant C++ ObjC++ Var(warn_zero_as_null_pointer_constant) Warning Warn when a literal '0' is used as null pointer +Wuseless-cast +C++ ObjC++ Var(warn_useless_cast) Warning +Warn about useless casts + ansi C ObjC C++ ObjC++ A synonym for -std=c89 (for C) or -std=c++98 (for C++) Index: testsuite/g++.dg/warn/Wuseless-cast.C =================================================================== --- testsuite/g++.dg/warn/Wuseless-cast.C (revision 0) +++ testsuite/g++.dg/warn/Wuseless-cast.C (revision 0) @@ -0,0 +1,62 @@ +// { dg-options "-Wuseless-cast" } + +template<typename T> + void tmpl_f1(T t) + { + (int)(t); + static_cast<int>(t); + reinterpret_cast<int>(t); + } + +struct A { }; + +template<typename T> + void tmpl_f2(T& t) + { + (A*)(&t); + const_cast<A*>(&t); + static_cast<A*>(&t); + reinterpret_cast<A*>(&t); + dynamic_cast<A*>(&t); + } + +template<typename T> + void tmpl_f3(T& t) + { + (A&)(t); + const_cast<A&>(t); + static_cast<A&>(t); + reinterpret_cast<A&>(t); + dynamic_cast<A&>(t); + } + +void f() +{ + int n; + + (int)(n); // { dg-warning "useless cast" } + static_cast<int>(n); // { dg-warning "useless cast" } + reinterpret_cast<int>(n); // { dg-warning "useless cast" } + + tmpl_f1(n); + + A a; + + (A*)(&a); // { dg-warning "useless cast" } + const_cast<A*>(&a); // { dg-warning "useless cast" } + static_cast<A*>(&a); // { dg-warning "useless cast" } + reinterpret_cast<A*>(&a); // { dg-warning "useless cast" } + dynamic_cast<A*>(&a); // { dg-warning "useless cast" } + + tmpl_f2(a); + + A& b = a; + + (A&)(b); // { dg-warning "useless cast" } + const_cast<A&>(b); // { dg-warning "useless cast" } + static_cast<A&>(b); // { dg-warning "useless cast" } + reinterpret_cast<A&>(b); // { dg-warning "useless cast" } + dynamic_cast<A&>(b); // { dg-warning "useless cast" } + + tmpl_f3(b); +} Index: cp/typeck.c =================================================================== --- cp/typeck.c (revision 185473) +++ cp/typeck.c (working copy) @@ -5749,6 +5749,24 @@ check_for_casting_away_constness (tree src_type, t } } +/* + Warns if the cast from expression EXPR to type TYPE is useless. + */ +void +maybe_warn_about_useless_cast (tree type, tree expr, tsubst_flags_t complain) +{ + if (complain & tf_warning + && c_inhibit_evaluation_warnings == 0) + { + if (REFERENCE_REF_P (expr)) + expr = TREE_OPERAND (expr, 0); + + if (same_type_p (TREE_TYPE (expr), type)) + warning (OPT_Wuseless_cast, "useless cast from type %qT to itself", + type); + } +} + /* Convert EXPR (an expression with pointer-to-member type) to TYPE (another pointer-to-member type in the same hierarchy) and return the converted expression. If ALLOW_INVERSE_P is permitted, a @@ -6078,7 +6096,11 @@ build_static_cast (tree type, tree expr, tsubst_fl result = build_static_cast_1 (type, expr, /*c_cast_p=*/false, &valid_p, complain); if (valid_p) - return result; + { + if (result != error_mark_node) + maybe_warn_about_useless_cast (type, expr, complain); + return result; + } if (complain & tf_error) error ("invalid static_cast from type %qT to type %qT", @@ -6305,6 +6327,8 @@ build_reinterpret_cast_1 (tree type, tree expr, bo tree build_reinterpret_cast (tree type, tree expr, tsubst_flags_t complain) { + tree r; + if (type == error_mark_node || expr == error_mark_node) return error_mark_node; @@ -6319,8 +6343,11 @@ build_reinterpret_cast (tree type, tree expr, tsub return convert_from_reference (t); } - return build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false, - /*valid_p=*/NULL, complain); + r = build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false, + /*valid_p=*/NULL, complain); + if (r != error_mark_node) + maybe_warn_about_useless_cast (type, expr, complain); + return r; } /* Perform a const_cast from EXPR to TYPE. If the cast is valid, @@ -6464,6 +6491,8 @@ build_const_cast_1 (tree dst_type, tree expr, tsub tree build_const_cast (tree type, tree expr, tsubst_flags_t complain) { + tree r; + if (type == error_mark_node || error_operand_p (expr)) return error_mark_node; @@ -6478,8 +6507,10 @@ build_const_cast (tree type, tree expr, tsubst_fla return convert_from_reference (t); } - return build_const_cast_1 (type, expr, complain, - /*valid_p=*/NULL); + r = build_const_cast_1 (type, expr, complain, /*valid_p=*/NULL); + if (r != error_mark_node) + maybe_warn_about_useless_cast (type, expr, complain); + return r; } /* Like cp_build_c_cast, but for the c-common bits. */ @@ -6567,7 +6598,11 @@ cp_build_c_cast (tree type, tree expr, tsubst_flag result = build_const_cast_1 (type, value, complain & tf_warning, &valid_p); if (valid_p) - return result; + { + if (result != error_mark_node) + maybe_warn_about_useless_cast (type, value, complain); + return result; + } /* Or a static cast. */ result = build_static_cast_1 (type, value, /*c_cast_p=*/true, @@ -6580,11 +6615,13 @@ cp_build_c_cast (tree type, tree expr, tsubst_flag const_cast. */ if (valid_p /* A valid cast may result in errors if, for example, a - conversion to am ambiguous base class is required. */ + conversion to an ambiguous base class is required. */ && !error_operand_p (result)) { tree result_type; + maybe_warn_about_useless_cast (type, value, complain); + /* Non-class rvalues always have cv-unqualified type. */ if (!CLASS_TYPE_P (type)) type = TYPE_MAIN_VARIANT (type); Index: cp/rtti.c =================================================================== --- cp/rtti.c (revision 185473) +++ cp/rtti.c (working copy) @@ -1,6 +1,6 @@ /* RunTime Type Identification Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Mostly written by Jason Merrill (jason@cygnus.com). @@ -774,6 +774,8 @@ build_dynamic_cast_1 (tree type, tree expr, tsubst tree build_dynamic_cast (tree type, tree expr, tsubst_flags_t complain) { + tree r; + if (type == error_mark_node || expr == error_mark_node) return error_mark_node; @@ -784,9 +786,12 @@ build_dynamic_cast (tree type, tree expr, tsubst_f return convert_from_reference (expr); } - return convert_from_reference (build_dynamic_cast_1 (type, expr, complain)); + r = convert_from_reference (build_dynamic_cast_1 (type, expr, complain)); + if (r != error_mark_node) + maybe_warn_about_useless_cast (type, expr, complain); + return r; } -\f + /* Return the runtime bit mask encoding the qualifiers of TYPE. */ static int Index: cp/pt.c =================================================================== --- cp/pt.c (revision 185473) +++ cp/pt.c (working copy) @@ -13444,7 +13444,7 @@ tsubst_copy_and_build (tree t, case STATIC_CAST_EXPR: { tree type; - tree op; + tree op, r = NULL_TREE; type = tsubst (TREE_TYPE (t), args, complain, in_decl); if (integral_constant_expression_p @@ -13458,21 +13458,30 @@ tsubst_copy_and_build (tree t, op = RECUR (TREE_OPERAND (t, 0)); + ++c_inhibit_evaluation_warnings; switch (TREE_CODE (t)) { case CAST_EXPR: - return build_functional_cast (type, op, complain); + r = build_functional_cast (type, op, complain); + break; case REINTERPRET_CAST_EXPR: - return build_reinterpret_cast (type, op, complain); + r = build_reinterpret_cast (type, op, complain); + break; case CONST_CAST_EXPR: - return build_const_cast (type, op, complain); + r = build_const_cast (type, op, complain); + break; case DYNAMIC_CAST_EXPR: - return build_dynamic_cast (type, op, complain); + r = build_dynamic_cast (type, op, complain); + break; case STATIC_CAST_EXPR: - return build_static_cast (type, op, complain); + r = build_static_cast (type, op, complain); + break; default: gcc_unreachable (); } + --c_inhibit_evaluation_warnings; + + return r; } case POSTDECREMENT_EXPR: Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 185473) +++ cp/cp-tree.h (working copy) @@ -5860,6 +5860,7 @@ extern int lvalue_or_else (tree, enum lvalue_use extern void check_template_keyword (tree); extern bool check_raw_literal_operator (const_tree decl); extern bool check_literal_operator_args (const_tree, bool *, bool *); +extern void maybe_warn_about_useless_cast (tree, tree, tsubst_flags_t); /* in typeck2.c */ extern void require_complete_eh_spec_types (tree, tree); ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [C++ Patch] PR 14710 (add -Wuseless-cast) 2012-03-16 21:45 [C++ Patch] PR 14710 (add -Wuseless-cast) Paolo Carlini @ 2012-03-17 16:04 ` Jason Merrill 2012-03-18 15:35 ` Paolo Carlini 0 siblings, 1 reply; 7+ messages in thread From: Jason Merrill @ 2012-03-17 16:04 UTC (permalink / raw) To: Paolo Carlini; +Cc: gcc-patches On 03/16/2012 05:42 PM, Paolo Carlini wrote: > 3- References can be easily missed because wrapped in INDIRECT_REF: as > explained at the beginning of tree.c and already used in many places, a > REFERENCE_REF_P check (and in case a TREE_OPERAND (expr, 0)) takes care > of that. I'm not 100% sure the solution is fully general, though. That won't catch something like int i; static_cast<int&>(i); which is also a useless cast, because i is already an int lvalue; not all lvalues are derived from references. Note that something like static_cast<int&&>(42); is not a useless cast, because it turns a prvalue into an xvalue. Jason ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [C++ Patch] PR 14710 (add -Wuseless-cast) 2012-03-17 16:04 ` Jason Merrill @ 2012-03-18 15:35 ` Paolo Carlini 2012-03-19 13:17 ` Jason Merrill 0 siblings, 1 reply; 7+ messages in thread From: Paolo Carlini @ 2012-03-18 15:35 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches [-- Attachment #1: Type: text/plain, Size: 560 bytes --] Hi, > That won't catch something like > > int i; > static_cast<int&>(i); > > which is also a useless cast, because i is already an int lvalue; not > all lvalues are derived from references. Note that something like > > static_cast<int&&>(42); > > is not a useless cast, because it turns a prvalue into an xvalue. Agreed. In order to handle correctly such cases I modified the check per the below. I also gated the not-so-trivial work with warn_useless_cast and extended the testcase. As usual, tested x86_64-linux. Thanks, Paolo. ////////////////////// [-- Attachment #2: patch_14710_2 --] [-- Type: text/plain, Size: 12427 bytes --] Index: doc/invoke.texi =================================================================== --- doc/invoke.texi (revision 185505) +++ doc/invoke.texi (working copy) @@ -274,8 +274,8 @@ Objective-C and Objective-C++ Dialects}. -Wunused-label -Wunused-local-typedefs -Wunused-parameter @gol -Wno-unused-result -Wunused-value @gol -Wunused-variable @gol -Wunused-but-set-parameter -Wunused-but-set-variable @gol --Wvariadic-macros -Wvector-operation-performance -Wvla --Wvolatile-register-var -Wwrite-strings -Wzero-as-null-pointer-constant} +-Wuseless-cast -Wvariadic-macros -Wvector-operation-performance @gol +-Wvla -Wvolatile-register-var -Wwrite-strings -Wzero-as-null-pointer-constant} @item C and Objective-C-only Warning Options @gccoptlist{-Wbad-function-cast -Wmissing-declarations @gol @@ -4199,6 +4199,11 @@ types. @option{-Wconversion-null} is enabled by de Warn when a literal '0' is used as null pointer constant. This can be useful to facilitate the conversion to @code{nullptr} in C++11. +@item -Wuseless-cast @r{(C++ and Objective-C++ only)} +@opindex Wuseless-cast +@opindex Wno-useless-cast +Warn when an expression is casted to its own type. + @item -Wempty-body @opindex Wempty-body @opindex Wno-empty-body Index: c-family/c.opt =================================================================== --- c-family/c.opt (revision 185505) +++ c-family/c.opt (working copy) @@ -697,6 +697,10 @@ Wzero-as-null-pointer-constant C++ ObjC++ Var(warn_zero_as_null_pointer_constant) Warning Warn when a literal '0' is used as null pointer +Wuseless-cast +C++ ObjC++ Var(warn_useless_cast) Warning +Warn about useless casts + ansi C ObjC C++ ObjC++ A synonym for -std=c89 (for C) or -std=c++98 (for C++) Index: testsuite/g++.dg/warn/Wuseless-cast.C =================================================================== --- testsuite/g++.dg/warn/Wuseless-cast.C (revision 0) +++ testsuite/g++.dg/warn/Wuseless-cast.C (revision 0) @@ -0,0 +1,123 @@ +// { dg-options "-Wuseless-cast" } + +template<typename T> + void tmpl_f1(T& t) + { + (int)(t); + static_cast<int>(t); + reinterpret_cast<int>(t); + + (int*)(&t); + const_cast<int*>(&t); + static_cast<int*>(&t); + reinterpret_cast<int*>(&t); + + (int&)(t); + const_cast<int&>(t); + static_cast<int&>(t); + reinterpret_cast<int&>(t); + } + +template<typename T> + void tmpl_f2(T t) + { + (int&)(t); + const_cast<int&>(t); + static_cast<int&>(t); + reinterpret_cast<int&>(t); + } + +struct A { }; + +template<typename T> + void tmpl_f3(T& t) + { + (A)(t); + static_cast<A>(t); + + (A*)(&t); + const_cast<A*>(&t); + static_cast<A*>(&t); + reinterpret_cast<A*>(&t); + dynamic_cast<A*>(&t); + + (A&)(t); + const_cast<A&>(t); + static_cast<A&>(t); + reinterpret_cast<A&>(t); + dynamic_cast<A&>(t); + } + +template<typename T> + void tmpl_f4(T t) + { + (A&)(t); + const_cast<A&>(t); + static_cast<A&>(t); + reinterpret_cast<A&>(t); + dynamic_cast<A&>(t); + } + +void f() +{ + int n; + + (int)(n); // { dg-warning "useless cast" } + static_cast<int>(n); // { dg-warning "useless cast" } + reinterpret_cast<int>(n); // { dg-warning "useless cast" } + + (int*)(&n); // { dg-warning "useless cast" } + const_cast<int*>(&n); // { dg-warning "useless cast" } + static_cast<int*>(&n); // { dg-warning "useless cast" } + reinterpret_cast<int*>(&n); // { dg-warning "useless cast" } + + int& m = n; + + (int&)(m); // { dg-warning "useless cast" } + const_cast<int&>(m); // { dg-warning "useless cast" } + static_cast<int&>(m); // { dg-warning "useless cast" } + reinterpret_cast<int&>(m); // { dg-warning "useless cast" } + + tmpl_f1(m); + + (int&)(n); // { dg-warning "useless cast" } + const_cast<int&>(n); // { dg-warning "useless cast" } + static_cast<int&>(n); // { dg-warning "useless cast" } + reinterpret_cast<int&>(n); // { dg-warning "useless cast" } + + tmpl_f2(n); + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + (int&&)(42); + static_cast<int&&>(42); +#endif + + A a; + + (A)(a); // { dg-warning "useless cast" } + static_cast<A>(a); // { dg-warning "useless cast" } + + (A*)(&a); // { dg-warning "useless cast" } + const_cast<A*>(&a); // { dg-warning "useless cast" } + static_cast<A*>(&a); // { dg-warning "useless cast" } + reinterpret_cast<A*>(&a); // { dg-warning "useless cast" } + dynamic_cast<A*>(&a); // { dg-warning "useless cast" } + + A& b = a; + + (A&)(b); // { dg-warning "useless cast" } + const_cast<A&>(b); // { dg-warning "useless cast" } + static_cast<A&>(b); // { dg-warning "useless cast" } + static_cast<A&>(b); // { dg-warning "useless cast" } + dynamic_cast<A&>(b); // { dg-warning "useless cast" } + + tmpl_f3(b); + + (A&)(a); // { dg-warning "useless cast" } + const_cast<A&>(a); // { dg-warning "useless cast" } + static_cast<A&>(a); // { dg-warning "useless cast" } + reinterpret_cast<A&>(a); // { dg-warning "useless cast" } + dynamic_cast<A&>(a); // { dg-warning "useless cast" } + + tmpl_f4(a); +} Index: cp/typeck.c =================================================================== --- cp/typeck.c (revision 185505) +++ cp/typeck.c (working copy) @@ -5749,6 +5749,27 @@ check_for_casting_away_constness (tree src_type, t } } +/* + Warns if the cast from expression EXPR to type TYPE is useless. + */ +void +maybe_warn_about_useless_cast (tree type, tree expr, tsubst_flags_t complain) +{ + if (warn_useless_cast + && complain & tf_warning + && c_inhibit_evaluation_warnings == 0) + { + if (REFERENCE_REF_P (expr)) + expr = TREE_OPERAND (expr, 0); + + if ((TREE_CODE (type) == REFERENCE_TYPE + && lvalue_p (expr) + && same_type_p (TREE_TYPE (expr), TREE_TYPE (type))) + || same_type_p (TREE_TYPE (expr), type)) + warning (OPT_Wuseless_cast, "useless cast to type %qT", type); + } +} + /* Convert EXPR (an expression with pointer-to-member type) to TYPE (another pointer-to-member type in the same hierarchy) and return the converted expression. If ALLOW_INVERSE_P is permitted, a @@ -6078,7 +6099,11 @@ build_static_cast (tree type, tree expr, tsubst_fl result = build_static_cast_1 (type, expr, /*c_cast_p=*/false, &valid_p, complain); if (valid_p) - return result; + { + if (result != error_mark_node) + maybe_warn_about_useless_cast (type, expr, complain); + return result; + } if (complain & tf_error) error ("invalid static_cast from type %qT to type %qT", @@ -6305,6 +6330,8 @@ build_reinterpret_cast_1 (tree type, tree expr, bo tree build_reinterpret_cast (tree type, tree expr, tsubst_flags_t complain) { + tree r; + if (type == error_mark_node || expr == error_mark_node) return error_mark_node; @@ -6319,8 +6346,11 @@ build_reinterpret_cast (tree type, tree expr, tsub return convert_from_reference (t); } - return build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false, - /*valid_p=*/NULL, complain); + r = build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false, + /*valid_p=*/NULL, complain); + if (r != error_mark_node) + maybe_warn_about_useless_cast (type, expr, complain); + return r; } /* Perform a const_cast from EXPR to TYPE. If the cast is valid, @@ -6464,6 +6494,8 @@ build_const_cast_1 (tree dst_type, tree expr, tsub tree build_const_cast (tree type, tree expr, tsubst_flags_t complain) { + tree r; + if (type == error_mark_node || error_operand_p (expr)) return error_mark_node; @@ -6478,8 +6510,10 @@ build_const_cast (tree type, tree expr, tsubst_fla return convert_from_reference (t); } - return build_const_cast_1 (type, expr, complain, - /*valid_p=*/NULL); + r = build_const_cast_1 (type, expr, complain, /*valid_p=*/NULL); + if (r != error_mark_node) + maybe_warn_about_useless_cast (type, expr, complain); + return r; } /* Like cp_build_c_cast, but for the c-common bits. */ @@ -6567,7 +6601,11 @@ cp_build_c_cast (tree type, tree expr, tsubst_flag result = build_const_cast_1 (type, value, complain & tf_warning, &valid_p); if (valid_p) - return result; + { + if (result != error_mark_node) + maybe_warn_about_useless_cast (type, value, complain); + return result; + } /* Or a static cast. */ result = build_static_cast_1 (type, value, /*c_cast_p=*/true, @@ -6580,11 +6618,13 @@ cp_build_c_cast (tree type, tree expr, tsubst_flag const_cast. */ if (valid_p /* A valid cast may result in errors if, for example, a - conversion to am ambiguous base class is required. */ + conversion to an ambiguous base class is required. */ && !error_operand_p (result)) { tree result_type; + maybe_warn_about_useless_cast (type, value, complain); + /* Non-class rvalues always have cv-unqualified type. */ if (!CLASS_TYPE_P (type)) type = TYPE_MAIN_VARIANT (type); Index: cp/rtti.c =================================================================== --- cp/rtti.c (revision 185505) +++ cp/rtti.c (working copy) @@ -1,6 +1,6 @@ /* RunTime Type Identification Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Mostly written by Jason Merrill (jason@cygnus.com). @@ -774,6 +774,8 @@ build_dynamic_cast_1 (tree type, tree expr, tsubst tree build_dynamic_cast (tree type, tree expr, tsubst_flags_t complain) { + tree r; + if (type == error_mark_node || expr == error_mark_node) return error_mark_node; @@ -784,9 +786,12 @@ build_dynamic_cast (tree type, tree expr, tsubst_f return convert_from_reference (expr); } - return convert_from_reference (build_dynamic_cast_1 (type, expr, complain)); + r = convert_from_reference (build_dynamic_cast_1 (type, expr, complain)); + if (r != error_mark_node) + maybe_warn_about_useless_cast (type, expr, complain); + return r; } -\f + /* Return the runtime bit mask encoding the qualifiers of TYPE. */ static int Index: cp/pt.c =================================================================== --- cp/pt.c (revision 185505) +++ cp/pt.c (working copy) @@ -13444,7 +13444,7 @@ tsubst_copy_and_build (tree t, case STATIC_CAST_EXPR: { tree type; - tree op; + tree op, r = NULL_TREE; type = tsubst (TREE_TYPE (t), args, complain, in_decl); if (integral_constant_expression_p @@ -13458,21 +13458,30 @@ tsubst_copy_and_build (tree t, op = RECUR (TREE_OPERAND (t, 0)); + ++c_inhibit_evaluation_warnings; switch (TREE_CODE (t)) { case CAST_EXPR: - return build_functional_cast (type, op, complain); + r = build_functional_cast (type, op, complain); + break; case REINTERPRET_CAST_EXPR: - return build_reinterpret_cast (type, op, complain); + r = build_reinterpret_cast (type, op, complain); + break; case CONST_CAST_EXPR: - return build_const_cast (type, op, complain); + r = build_const_cast (type, op, complain); + break; case DYNAMIC_CAST_EXPR: - return build_dynamic_cast (type, op, complain); + r = build_dynamic_cast (type, op, complain); + break; case STATIC_CAST_EXPR: - return build_static_cast (type, op, complain); + r = build_static_cast (type, op, complain); + break; default: gcc_unreachable (); } + --c_inhibit_evaluation_warnings; + + return r; } case POSTDECREMENT_EXPR: Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 185505) +++ cp/cp-tree.h (working copy) @@ -5860,6 +5860,7 @@ extern int lvalue_or_else (tree, enum lvalue_use extern void check_template_keyword (tree); extern bool check_raw_literal_operator (const_tree decl); extern bool check_literal_operator_args (const_tree, bool *, bool *); +extern void maybe_warn_about_useless_cast (tree, tree, tsubst_flags_t); /* in typeck2.c */ extern void require_complete_eh_spec_types (tree, tree); ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [C++ Patch] PR 14710 (add -Wuseless-cast) 2012-03-18 15:35 ` Paolo Carlini @ 2012-03-19 13:17 ` Jason Merrill 2012-03-19 13:57 ` Paolo Carlini 0 siblings, 1 reply; 7+ messages in thread From: Jason Merrill @ 2012-03-19 13:17 UTC (permalink / raw) To: Paolo Carlini; +Cc: gcc-patches On 03/18/2012 11:32 AM, Paolo Carlini wrote: > + if ((TREE_CODE (type) == REFERENCE_TYPE > + && lvalue_p (expr) > + && same_type_p (TREE_TYPE (expr), TREE_TYPE (type))) > + || same_type_p (TREE_TYPE (expr), type)) > + warning (OPT_Wuseless_cast, "useless cast to type %qT", type); I think instead of just lvalue_p (expr) you want TYPE_REF_IS_RVALUE (type) ? xvalue_p (expr) : real_lvalue_p (expr) where xvalue_p is a new function that just does return lvalue_kind (expr) == clk_rvalueref; Jason ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [C++ Patch] PR 14710 (add -Wuseless-cast) 2012-03-19 13:17 ` Jason Merrill @ 2012-03-19 13:57 ` Paolo Carlini 2012-03-19 14:59 ` Jason Merrill 0 siblings, 1 reply; 7+ messages in thread From: Paolo Carlini @ 2012-03-19 13:57 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches [-- Attachment #1: Type: text/plain, Size: 684 bytes --] On 03/19/2012 02:17 PM, Jason Merrill wrote: > On 03/18/2012 11:32 AM, Paolo Carlini wrote: >> + if ((TREE_CODE (type) == REFERENCE_TYPE >> + && lvalue_p (expr) >> + && same_type_p (TREE_TYPE (expr), TREE_TYPE (type))) >> + || same_type_p (TREE_TYPE (expr), type)) >> + warning (OPT_Wuseless_cast, "useless cast to type %qT", type); > > I think instead of just lvalue_p (expr) you want > > TYPE_REF_IS_RVALUE (type) ? xvalue_p (expr) : real_lvalue_p (expr) > > where xvalue_p is a new function that just does > > return lvalue_kind (expr) == clk_rvalueref; Ah, thanks. Then I tested on x86_64-linux the below. Ok now? Thanks again, Paolo. ////////////////////// [-- Attachment #2: CL_14710_3 --] [-- Type: text/plain, Size: 858 bytes --] 2012-03-19 Paolo Carlini <paolo.carlini@oracle.com> PR c++/14710 * doc/invoke.texi: Document -Wuseless-cast. /c-family 2012-03-19 Paolo Carlini <paolo.carlini@oracle.com> PR c++/14710 * c.opt ([Wuseless-cast]): Add. /cp 2012-03-19 Paolo Carlini <paolo.carlini@oracle.com> PR c++/14710 * cp-tree.h (xvalue_p, maybe_warn_about_useless_cast): Declare. * tree.c (xvalue_p): Define. * typeck.c (maybe_warn_about_useless_cast): Define. (build_reinterpret_cast, build_const_cast, build_static_cast, cp_build_c_cast): Use maybe_warn_about_useless_cast. * rtti.c (build_dynamic_cast): Likewise. * pt.c (tsubst_copy_and_build, case CAST_EXPR): Increment/decrement c_inhibit_evaluation_warnings before/after the build_* calls. /testsuite 2012-03-19 Paolo Carlini <paolo.carlini@oracle.com> PR c++/14710 * g++.dg/warn/Wuseless-cast.C: New. [-- Attachment #3: patch_14710_3 --] [-- Type: text/plain, Size: 14229 bytes --] Index: doc/invoke.texi =================================================================== --- doc/invoke.texi (revision 185519) +++ doc/invoke.texi (working copy) @@ -274,8 +274,8 @@ Objective-C and Objective-C++ Dialects}. -Wunused-label -Wunused-local-typedefs -Wunused-parameter @gol -Wno-unused-result -Wunused-value @gol -Wunused-variable @gol -Wunused-but-set-parameter -Wunused-but-set-variable @gol --Wvariadic-macros -Wvector-operation-performance -Wvla --Wvolatile-register-var -Wwrite-strings -Wzero-as-null-pointer-constant} +-Wuseless-cast -Wvariadic-macros -Wvector-operation-performance @gol +-Wvla -Wvolatile-register-var -Wwrite-strings -Wzero-as-null-pointer-constant} @item C and Objective-C-only Warning Options @gccoptlist{-Wbad-function-cast -Wmissing-declarations @gol @@ -4199,6 +4199,11 @@ types. @option{-Wconversion-null} is enabled by de Warn when a literal '0' is used as null pointer constant. This can be useful to facilitate the conversion to @code{nullptr} in C++11. +@item -Wuseless-cast @r{(C++ and Objective-C++ only)} +@opindex Wuseless-cast +@opindex Wno-useless-cast +Warn when an expression is casted to its own type. + @item -Wempty-body @opindex Wempty-body @opindex Wno-empty-body Index: c-family/c.opt =================================================================== --- c-family/c.opt (revision 185519) +++ c-family/c.opt (working copy) @@ -697,6 +697,10 @@ Wzero-as-null-pointer-constant C++ ObjC++ Var(warn_zero_as_null_pointer_constant) Warning Warn when a literal '0' is used as null pointer +Wuseless-cast +C++ ObjC++ Var(warn_useless_cast) Warning +Warn about useless casts + ansi C ObjC C++ ObjC++ A synonym for -std=c89 (for C) or -std=c++98 (for C++) Index: testsuite/g++.dg/warn/Wuseless-cast.C =================================================================== --- testsuite/g++.dg/warn/Wuseless-cast.C (revision 0) +++ testsuite/g++.dg/warn/Wuseless-cast.C (revision 0) @@ -0,0 +1,123 @@ +// { dg-options "-Wuseless-cast" } + +template<typename T> + void tmpl_f1(T& t) + { + (int)(t); + static_cast<int>(t); + reinterpret_cast<int>(t); + + (int*)(&t); + const_cast<int*>(&t); + static_cast<int*>(&t); + reinterpret_cast<int*>(&t); + + (int&)(t); + const_cast<int&>(t); + static_cast<int&>(t); + reinterpret_cast<int&>(t); + } + +template<typename T> + void tmpl_f2(T t) + { + (int&)(t); + const_cast<int&>(t); + static_cast<int&>(t); + reinterpret_cast<int&>(t); + } + +struct A { }; + +template<typename T> + void tmpl_f3(T& t) + { + (A)(t); + static_cast<A>(t); + + (A*)(&t); + const_cast<A*>(&t); + static_cast<A*>(&t); + reinterpret_cast<A*>(&t); + dynamic_cast<A*>(&t); + + (A&)(t); + const_cast<A&>(t); + static_cast<A&>(t); + reinterpret_cast<A&>(t); + dynamic_cast<A&>(t); + } + +template<typename T> + void tmpl_f4(T t) + { + (A&)(t); + const_cast<A&>(t); + static_cast<A&>(t); + reinterpret_cast<A&>(t); + dynamic_cast<A&>(t); + } + +void f() +{ + int n; + + (int)(n); // { dg-warning "useless cast" } + static_cast<int>(n); // { dg-warning "useless cast" } + reinterpret_cast<int>(n); // { dg-warning "useless cast" } + + (int*)(&n); // { dg-warning "useless cast" } + const_cast<int*>(&n); // { dg-warning "useless cast" } + static_cast<int*>(&n); // { dg-warning "useless cast" } + reinterpret_cast<int*>(&n); // { dg-warning "useless cast" } + + int& m = n; + + (int&)(m); // { dg-warning "useless cast" } + const_cast<int&>(m); // { dg-warning "useless cast" } + static_cast<int&>(m); // { dg-warning "useless cast" } + reinterpret_cast<int&>(m); // { dg-warning "useless cast" } + + tmpl_f1(m); + + (int&)(n); // { dg-warning "useless cast" } + const_cast<int&>(n); // { dg-warning "useless cast" } + static_cast<int&>(n); // { dg-warning "useless cast" } + reinterpret_cast<int&>(n); // { dg-warning "useless cast" } + + tmpl_f2(n); + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + (int&&)(42); + static_cast<int&&>(42); +#endif + + A a; + + (A)(a); // { dg-warning "useless cast" } + static_cast<A>(a); // { dg-warning "useless cast" } + + (A*)(&a); // { dg-warning "useless cast" } + const_cast<A*>(&a); // { dg-warning "useless cast" } + static_cast<A*>(&a); // { dg-warning "useless cast" } + reinterpret_cast<A*>(&a); // { dg-warning "useless cast" } + dynamic_cast<A*>(&a); // { dg-warning "useless cast" } + + A& b = a; + + (A&)(b); // { dg-warning "useless cast" } + const_cast<A&>(b); // { dg-warning "useless cast" } + static_cast<A&>(b); // { dg-warning "useless cast" } + static_cast<A&>(b); // { dg-warning "useless cast" } + dynamic_cast<A&>(b); // { dg-warning "useless cast" } + + tmpl_f3(b); + + (A&)(a); // { dg-warning "useless cast" } + const_cast<A&>(a); // { dg-warning "useless cast" } + static_cast<A&>(a); // { dg-warning "useless cast" } + reinterpret_cast<A&>(a); // { dg-warning "useless cast" } + dynamic_cast<A&>(a); // { dg-warning "useless cast" } + + tmpl_f4(a); +} Index: cp/typeck.c =================================================================== --- cp/typeck.c (revision 185519) +++ cp/typeck.c (working copy) @@ -5749,6 +5749,28 @@ check_for_casting_away_constness (tree src_type, t } } +/* + Warns if the cast from expression EXPR to type TYPE is useless. + */ +void +maybe_warn_about_useless_cast (tree type, tree expr, tsubst_flags_t complain) +{ + if (warn_useless_cast + && complain & tf_warning + && c_inhibit_evaluation_warnings == 0) + { + if (REFERENCE_REF_P (expr)) + expr = TREE_OPERAND (expr, 0); + + if ((TREE_CODE (type) == REFERENCE_TYPE + && (TYPE_REF_IS_RVALUE (type) + ? xvalue_p (expr) : real_lvalue_p (expr)) + && same_type_p (TREE_TYPE (expr), TREE_TYPE (type))) + || same_type_p (TREE_TYPE (expr), type)) + warning (OPT_Wuseless_cast, "useless cast to type %qT", type); + } +} + /* Convert EXPR (an expression with pointer-to-member type) to TYPE (another pointer-to-member type in the same hierarchy) and return the converted expression. If ALLOW_INVERSE_P is permitted, a @@ -6078,7 +6100,11 @@ build_static_cast (tree type, tree expr, tsubst_fl result = build_static_cast_1 (type, expr, /*c_cast_p=*/false, &valid_p, complain); if (valid_p) - return result; + { + if (result != error_mark_node) + maybe_warn_about_useless_cast (type, expr, complain); + return result; + } if (complain & tf_error) error ("invalid static_cast from type %qT to type %qT", @@ -6305,6 +6331,8 @@ build_reinterpret_cast_1 (tree type, tree expr, bo tree build_reinterpret_cast (tree type, tree expr, tsubst_flags_t complain) { + tree r; + if (type == error_mark_node || expr == error_mark_node) return error_mark_node; @@ -6319,8 +6347,11 @@ build_reinterpret_cast (tree type, tree expr, tsub return convert_from_reference (t); } - return build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false, - /*valid_p=*/NULL, complain); + r = build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false, + /*valid_p=*/NULL, complain); + if (r != error_mark_node) + maybe_warn_about_useless_cast (type, expr, complain); + return r; } /* Perform a const_cast from EXPR to TYPE. If the cast is valid, @@ -6464,6 +6495,8 @@ build_const_cast_1 (tree dst_type, tree expr, tsub tree build_const_cast (tree type, tree expr, tsubst_flags_t complain) { + tree r; + if (type == error_mark_node || error_operand_p (expr)) return error_mark_node; @@ -6478,8 +6511,10 @@ build_const_cast (tree type, tree expr, tsubst_fla return convert_from_reference (t); } - return build_const_cast_1 (type, expr, complain, - /*valid_p=*/NULL); + r = build_const_cast_1 (type, expr, complain, /*valid_p=*/NULL); + if (r != error_mark_node) + maybe_warn_about_useless_cast (type, expr, complain); + return r; } /* Like cp_build_c_cast, but for the c-common bits. */ @@ -6567,7 +6602,11 @@ cp_build_c_cast (tree type, tree expr, tsubst_flag result = build_const_cast_1 (type, value, complain & tf_warning, &valid_p); if (valid_p) - return result; + { + if (result != error_mark_node) + maybe_warn_about_useless_cast (type, value, complain); + return result; + } /* Or a static cast. */ result = build_static_cast_1 (type, value, /*c_cast_p=*/true, @@ -6580,11 +6619,13 @@ cp_build_c_cast (tree type, tree expr, tsubst_flag const_cast. */ if (valid_p /* A valid cast may result in errors if, for example, a - conversion to am ambiguous base class is required. */ + conversion to an ambiguous base class is required. */ && !error_operand_p (result)) { tree result_type; + maybe_warn_about_useless_cast (type, value, complain); + /* Non-class rvalues always have cv-unqualified type. */ if (!CLASS_TYPE_P (type)) type = TYPE_MAIN_VARIANT (type); Index: cp/rtti.c =================================================================== --- cp/rtti.c (revision 185519) +++ cp/rtti.c (working copy) @@ -1,6 +1,6 @@ /* RunTime Type Identification Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Mostly written by Jason Merrill (jason@cygnus.com). @@ -774,6 +774,8 @@ build_dynamic_cast_1 (tree type, tree expr, tsubst tree build_dynamic_cast (tree type, tree expr, tsubst_flags_t complain) { + tree r; + if (type == error_mark_node || expr == error_mark_node) return error_mark_node; @@ -784,9 +786,12 @@ build_dynamic_cast (tree type, tree expr, tsubst_f return convert_from_reference (expr); } - return convert_from_reference (build_dynamic_cast_1 (type, expr, complain)); + r = convert_from_reference (build_dynamic_cast_1 (type, expr, complain)); + if (r != error_mark_node) + maybe_warn_about_useless_cast (type, expr, complain); + return r; } -\f + /* Return the runtime bit mask encoding the qualifiers of TYPE. */ static int Index: cp/tree.c =================================================================== --- cp/tree.c (revision 185519) +++ cp/tree.c (working copy) @@ -1,6 +1,7 @@ /* Language-dependent node constructors for parse phase of GNU compiler. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) @@ -274,6 +275,14 @@ lvalue_or_rvalue_with_address_p (const_tree ref) return (kind != clk_none); } +/* Returns true if REF is an xvalue, false otherwise. */ + +bool +xvalue_p (const_tree ref) +{ + return (lvalue_kind (ref) == clk_rvalueref); +} + /* Test whether DECL is a builtin that may appear in a constant-expression. */ Index: cp/pt.c =================================================================== --- cp/pt.c (revision 185519) +++ cp/pt.c (working copy) @@ -13444,7 +13444,7 @@ tsubst_copy_and_build (tree t, case STATIC_CAST_EXPR: { tree type; - tree op; + tree op, r = NULL_TREE; type = tsubst (TREE_TYPE (t), args, complain, in_decl); if (integral_constant_expression_p @@ -13458,21 +13458,30 @@ tsubst_copy_and_build (tree t, op = RECUR (TREE_OPERAND (t, 0)); + ++c_inhibit_evaluation_warnings; switch (TREE_CODE (t)) { case CAST_EXPR: - return build_functional_cast (type, op, complain); + r = build_functional_cast (type, op, complain); + break; case REINTERPRET_CAST_EXPR: - return build_reinterpret_cast (type, op, complain); + r = build_reinterpret_cast (type, op, complain); + break; case CONST_CAST_EXPR: - return build_const_cast (type, op, complain); + r = build_const_cast (type, op, complain); + break; case DYNAMIC_CAST_EXPR: - return build_dynamic_cast (type, op, complain); + r = build_dynamic_cast (type, op, complain); + break; case STATIC_CAST_EXPR: - return build_static_cast (type, op, complain); + r = build_static_cast (type, op, complain); + break; default: gcc_unreachable (); } + --c_inhibit_evaluation_warnings; + + return r; } case POSTDECREMENT_EXPR: Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 185519) +++ cp/cp-tree.h (working copy) @@ -1,6 +1,7 @@ /* Definitions for C++ parsing and type checking. Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) @@ -5661,6 +5662,7 @@ extern int member_p (const_tree); extern cp_lvalue_kind real_lvalue_p (const_tree); extern cp_lvalue_kind lvalue_kind (const_tree); extern bool lvalue_or_rvalue_with_address_p (const_tree); +extern bool xvalue_p (const_tree); extern bool builtin_valid_in_constant_expr_p (const_tree); extern tree build_min (enum tree_code, tree, ...); extern tree build_min_nt (enum tree_code, ...); @@ -5860,6 +5862,7 @@ extern int lvalue_or_else (tree, enum lvalue_use extern void check_template_keyword (tree); extern bool check_raw_literal_operator (const_tree decl); extern bool check_literal_operator_args (const_tree, bool *, bool *); +extern void maybe_warn_about_useless_cast (tree, tree, tsubst_flags_t); /* in typeck2.c */ extern void require_complete_eh_spec_types (tree, tree); ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [C++ Patch] PR 14710 (add -Wuseless-cast) 2012-03-19 13:57 ` Paolo Carlini @ 2012-03-19 14:59 ` Jason Merrill 2012-03-19 17:46 ` Paolo Carlini 0 siblings, 1 reply; 7+ messages in thread From: Jason Merrill @ 2012-03-19 14:59 UTC (permalink / raw) To: Paolo Carlini; +Cc: gcc-patches OK. Jason ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [C++ Patch] PR 14710 (add -Wuseless-cast) 2012-03-19 14:59 ` Jason Merrill @ 2012-03-19 17:46 ` Paolo Carlini 0 siblings, 0 replies; 7+ messages in thread From: Paolo Carlini @ 2012-03-19 17:46 UTC (permalink / raw) To: Jason Merrill; +Cc: gcc-patches [-- Attachment #1: Type: text/plain, Size: 216 bytes --] On 03/19/2012 03:59 PM, Jason Merrill wrote: > OK. Thanks. I committed the patch. I'm going to add, as obvious, the following few additional tests, which my previous iteration got wrong. Paolo. ////////////////// [-- Attachment #2: CL --] [-- Type: text/plain, Size: 98 bytes --] 2012-03-19 Paolo Carlini <paolo.carlini@oracle.com> * g++.dg/warn/Wuseless-cast.C: Extend. [-- Attachment #3: patchlet --] [-- Type: text/plain, Size: 552 bytes --] Index: testsuite/g++.dg/warn/Wuseless-cast.C =================================================================== --- testsuite/g++.dg/warn/Wuseless-cast.C (revision 185528) +++ testsuite/g++.dg/warn/Wuseless-cast.C (working copy) @@ -58,6 +58,8 @@ template<typename T> dynamic_cast<A&>(t); } +A prvalue(); + void f() { int n; @@ -90,6 +92,10 @@ void f() #ifdef __GXX_EXPERIMENTAL_CXX0X__ (int&&)(42); static_cast<int&&>(42); + + (A&&)(prvalue()); + const_cast<A&&>(prvalue()); + static_cast<A&&>(prvalue()); #endif A a; ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2012-03-19 17:46 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-03-16 21:45 [C++ Patch] PR 14710 (add -Wuseless-cast) Paolo Carlini 2012-03-17 16:04 ` Jason Merrill 2012-03-18 15:35 ` Paolo Carlini 2012-03-19 13:17 ` Jason Merrill 2012-03-19 13:57 ` Paolo Carlini 2012-03-19 14:59 ` Jason Merrill 2012-03-19 17:46 ` Paolo Carlini
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).