2012-03-16 Paolo Carlini <paolo.carlini@oracle.com>
authorpaolo <paolo@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 19 Mar 2012 15:51:25 +0000 (15:51 +0000)
committerpaolo <paolo@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 19 Mar 2012 15:51:25 +0000 (15:51 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@185524 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c.opt
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/cp/rtti.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/doc/invoke.texi
gcc/testsuite/g++.dg/warn/Wuseless-cast.C [new file with mode: 0644]

index 670361e..050d379 100644 (file)
@@ -1,3 +1,8 @@
+2012-03-19  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       PR c++/14710
+       * doc/invoke.texi: Document -Wuseless-cast.
+
 2012-03-19  Eric Botcazou  <ebotcazou@adacore.com>
 
        * tree.def (REALPART_EXPR, IMAGPART_EXPR, VIEW_CONVERT_EXPR): Move.
index dd7b77b..1b586e5 100644 (file)
@@ -1,3 +1,8 @@
+2012-03-19  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       PR c++/14710
+       * c.opt ([Wuseless-cast]): Add.
+
 2012-03-16  Richard Guenther  <rguenther@suse.de>
 
        * c-pretty-print.c (pp_c_initializer_list): Adjust.
index a14514a..1ec5504 100644 (file)
@@ -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 cf4d453..7908bb3 100644 (file)
@@ -1,3 +1,15 @@
+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.
+
 2012-03-15  Jason Merrill  <jason@redhat.com>
 
        PR c++/52582
index d24c596..fc60d86 100644 (file)
@@ -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);
index 6dd004e..b36e49d 100644 (file)
@@ -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 30383ed..2ca8fa5 100644 (file)
@@ -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_flags_t complain)
 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_flags_t complain)
       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 b80b52a..87e9be8 100644 (file)
@@ -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 643454c..d2d6c4e 100644 (file)
@@ -5749,6 +5749,28 @@ check_for_casting_away_constness (tree src_type, tree dest_type,
     }
 }
 
+/*
+  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_flags_t complain)
   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, bool c_cast_p,
 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, tsubst_flags_t complain)
       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, tsubst_flags_t complain,
 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_flags_t complain)
       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_flags_t complain)
   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_flags_t complain)
      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 8571a8b..bf821ff 100644 (file)
@@ -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 default.
 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
diff --git a/gcc/testsuite/g++.dg/warn/Wuseless-cast.C b/gcc/testsuite/g++.dg/warn/Wuseless-cast.C
new file mode 100644 (file)
index 0000000..8000d93
--- /dev/null
@@ -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);
+}