PR c++/80544 strip cv-quals from cast results
authorJonathan Wakely <jwakely@redhat.com>
Wed, 24 May 2017 22:16:59 +0000 (23:16 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 24 May 2017 22:16:59 +0000 (23:16 +0100)
gcc/cp:

PR c++/80544
* tree.c (reshape_init): Use unqualified type for direct enum init.
* typeck.c (maybe_warn_about_cast_ignoring_quals): New.
(build_static_cast_1, build_reinterpret_cast_1): Strip cv-quals from
non-class destination types.
(build_const_cast_1): Strip cv-quals from destination types.
(build_static_cast, build_reinterpret_cast, build_const_cast)
(cp_build_c_cast): Add calls to maybe_warn_about_cast_ignoring_quals.

gcc/testsuite:

PR c++/80544
* g++.dg/expr/cast11.C: New test.

From-SVN: r248432

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/expr/cast11.C [new file with mode: 0644]

index f2828f8d7eb6181a3d1d2a492dafd94b3ba55107..2982ca7e4817edeedd5ac24c0e5700cb8225dbe8 100644 (file)
@@ -1,3 +1,14 @@
+2017-05-24  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR c++/80544
+       * tree.c (reshape_init): Use unqualified type for direct enum init.
+       * typeck.c (maybe_warn_about_cast_ignoring_quals): New.
+       (build_static_cast_1, build_reinterpret_cast_1): Strip cv-quals from
+       non-class destination types.
+       (build_const_cast_1): Strip cv-quals from destination types.
+       (build_static_cast, build_reinterpret_cast, build_const_cast)
+       (cp_build_c_cast): Add calls to maybe_warn_about_cast_ignoring_quals.
+
 2017-05-24  Martin Sebor  <msebor@redhat.com>
 
        PR c/80731
index afd47bbc509c9966941294560b911dd6c6fff0da..3ff0130cc644d99d32e6f5d92685c165c073b681 100644 (file)
@@ -6043,6 +6043,7 @@ reshape_init (tree type, tree init, tsubst_flags_t complain)
   if (is_direct_enum_init (type, init))
     {
       tree elt = CONSTRUCTOR_ELT (init, 0)->value;
+      type = cv_unqualified (type);
       if (check_narrowing (ENUM_UNDERLYING_TYPE (type), elt, complain))
        return cp_build_c_cast (type, elt, tf_warning_or_error);
       else
index 13d90a6573d55481c63702c82f42e0c050e23325..b81d6c8fc786df96ad353b34eea059b76a218ace 100644 (file)
@@ -6655,9 +6655,7 @@ check_for_casting_away_constness (tree src_type, tree dest_type,
     }
 }
 
-/*
-  Warns if the cast from expression EXPR to type TYPE is useless.
- */
+/* 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)
 {
@@ -6673,6 +6671,20 @@ maybe_warn_about_useless_cast (tree type, tree expr, tsubst_flags_t complain)
     }
 }
 
+/* Warns if the cast ignores cv-qualifiers on TYPE.  */
+void
+maybe_warn_about_cast_ignoring_quals (tree type, tsubst_flags_t complain)
+{
+  if (warn_ignored_qualifiers
+      && complain & tf_warning
+      && !CLASS_TYPE_P (type)
+      && (cp_type_quals (type) & (TYPE_QUAL_CONST|TYPE_QUAL_VOLATILE)))
+    {
+      warning (OPT_Wignored_qualifiers, "type qualifiers ignored on cast "
+              "result 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
@@ -6746,6 +6758,10 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
   /* Save casted types in the function's used types hash table.  */
   used_types_insert (type);
 
+  /* A prvalue of non-class type is cv-unqualified.  */
+  if (!CLASS_TYPE_P (type))
+    type = cv_unqualified (type);
+
   /* [expr.static.cast]
 
      An lvalue of type "cv1 B", where B is a class type, can be cast
@@ -7035,7 +7051,10 @@ build_static_cast (tree type, tree expr, tsubst_flags_t complain)
   if (valid_p)
     {
       if (result != error_mark_node)
-       maybe_warn_about_useless_cast (type, expr, complain);
+       {
+         maybe_warn_about_useless_cast (type, expr, complain);
+         maybe_warn_about_cast_ignoring_quals (type, complain);
+       }
       return result;
     }
 
@@ -7108,6 +7127,10 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
   /* Save casted types in the function's used types hash table.  */
   used_types_insert (type);
 
+  /* A prvalue of non-class type is cv-unqualified.  */
+  if (!CLASS_TYPE_P (type))
+    type = cv_unqualified (type);
+
   /* [expr.reinterpret.cast]
      An lvalue expression of type T1 can be cast to the type
      "reference to T2" if an expression of type "pointer to T1" can be
@@ -7289,7 +7312,10 @@ build_reinterpret_cast (tree type, tree expr, tsubst_flags_t 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);
+    {
+      maybe_warn_about_useless_cast (type, expr, complain);
+      maybe_warn_about_cast_ignoring_quals (type, complain);
+    }
   return r;
 }
 
@@ -7335,6 +7361,9 @@ build_const_cast_1 (tree dst_type, tree expr, tsubst_flags_t complain,
       return error_mark_node;
     }
 
+  /* A prvalue of non-class type is cv-unqualified.  */
+  dst_type = cv_unqualified (dst_type);
+
   /* Save casted types in the function's used types hash table.  */
   used_types_insert (dst_type);
 
@@ -7455,7 +7484,10 @@ build_const_cast (tree type, tree expr, tsubst_flags_t complain)
 
   r = build_const_cast_1 (type, expr, complain, /*valid_p=*/NULL);
   if (r != error_mark_node)
-    maybe_warn_about_useless_cast (type, expr, complain);
+    {
+      maybe_warn_about_useless_cast (type, expr, complain);
+      maybe_warn_about_cast_ignoring_quals (type, complain);
+    }
   return r;
 }
 
@@ -7558,7 +7590,10 @@ cp_build_c_cast (tree type, tree expr, tsubst_flags_t complain)
   if (valid_p)
     {
       if (result != error_mark_node)
-       maybe_warn_about_useless_cast (type, value, complain);
+       {
+         maybe_warn_about_useless_cast (type, value, complain);
+         maybe_warn_about_cast_ignoring_quals (type, complain);
+       }
       return result;
     }
 
@@ -7579,6 +7614,7 @@ cp_build_c_cast (tree type, tree expr, tsubst_flags_t complain)
       tree result_type;
 
       maybe_warn_about_useless_cast (type, value, complain);
+      maybe_warn_about_cast_ignoring_quals (type, complain);
 
       /* Non-class rvalues always have cv-unqualified type.  */
       if (!CLASS_TYPE_P (type))
index 003dfa1b2d7bad337723668f7eed57205a33cb78..cc8e09d9a229488d3de1c5a36bc9d4c69f2f5cbc 100644 (file)
@@ -1,3 +1,8 @@
+2017-05-24  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR c++/80544
+       * g++.dg/expr/cast11.C: New test.
+
 2017-05-24  Martin Sebor  <msebor@redhat.com>
 
        PR c/80731
diff --git a/gcc/testsuite/g++.dg/expr/cast11.C b/gcc/testsuite/g++.dg/expr/cast11.C
new file mode 100644 (file)
index 0000000..01d578a
--- /dev/null
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wignored-qualifiers" }
+// c++/80544 cast expressions returned cv-qualified prvalues
+
+template<typename T> void f(T&&) { }
+template<typename T> void f(T const&&) = delete;
+
+template<typename T> void g(T&&) = delete;
+template<typename T> void g(T const&&) { }
+
+struct B { int i; const char c; } b = {};
+
+void f1()
+{
+  int i = 0;
+  f((long const)i);                    // { dg-warning "qualifiers ignored" }
+  f((int* const)&i);                   // { dg-warning "qualifiers ignored" }
+  f((int const* const)&i);             // { dg-warning "qualifiers ignored" }
+  f((long* const)&i);                  // { dg-warning "qualifiers ignored" }
+
+  f(static_cast<long const>(i));       // { dg-warning "qualifiers ignored" }
+  f(reinterpret_cast<long const>(&i)); // { dg-warning "qualifiers ignored" }
+
+  f(static_cast<int* const>(&i));      // { dg-warning "qualifiers ignored" }
+  f(const_cast<int* const>(&i));       // { dg-warning "qualifiers ignored" }
+  f(reinterpret_cast<long* const>(&i));        // { dg-warning "qualifiers ignored" }
+
+  using ptrmem = int B::*;
+  f(static_cast<ptrmem const>(&B::i)); // { dg-warning "qualifiers ignored" }
+  f(const_cast<ptrmem const>(&B::i));  // { dg-warning "qualifiers ignored" }
+  f(reinterpret_cast<ptrmem const>(&B::i)); // { dg-warning "qualifiers ignored" }
+
+  // No warnings, not a cv-qualified type:
+  using ptrmem2 = const char B::*;
+  f(static_cast<ptrmem2>(&B::c));
+  f(const_cast<ptrmem2>(&B::c));
+  f(reinterpret_cast<ptrmem2>(&B::c));
+
+  // prvalue of class type can have cv-quals:
+  g(static_cast<const B>(b));
+}