On 23/05/17 16:26 -0400, Jason Merrill wrote:
On Tue, May 23, 2017 at 2:00 PM, Jonathan Wakely <jwak...@redhat.com> wrote:
On 19/05/17 15:14 -0400, Jason Merrill wrote:

On Thu, Apr 27, 2017 at 12:59 PM, Jonathan Wakely <jwak...@redhat.com>
wrote:

I also tried to add a warning like EDG's (see the PR) but it gave a
false positive for direct-list-init of scoped enums (P0138R2, r240449)
because that code goes through build_c_cast to perform the conversion,
so looks like a cast to my new warning.


The enum init code could strip the cv-quals when calling build_c_cast
to avoid the warning.


Thanks, that works. I don't think this warning fits under any existing
option, so I'll add a new one. -Wuseless-cast-qual maybe? Or is that
too close to -Wuseless-cast and -Wcast-qual and would cause confusion?

-Wcast-rvalue-qual ?

I realised that -Wignored-qualifiers is a good fit. That warns about
ignored cv-qualifiers on return types, which is a very similar case.

This patch adds a new function to conditionally warn and calls that
from the build_*_cast functions after they produce a valid result. I
originally put the warnings next to the cv_unqualified calls that
strip the quals, but was getting duplicate warnings when build_cp_cast
calls more than one of the build_*_cast_1 functions.

This also removes the unnecessary check for reference types that
Nathan pointed out.

Tested x86_64-linux and powerpc64-linux. OK for trunk?


commit dddbdfbdc8de6565b45a6d794148dfe077d83d49
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Wed May 24 14:09:36 2017 +0100

    PR c++/80544 strip cv-quals from cast results
    
    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.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index afd47bb..3ff0130 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 13d90a6..ecc7190 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -6673,6 +6673,22 @@ 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 +6762,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 +7055,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 +7131,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 +7316,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 +7365,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 +7488,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 +7594,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 +7618,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))
diff --git a/gcc/testsuite/g++.dg/expr/cast11.C b/gcc/testsuite/g++.dg/expr/cast11.C
new file mode 100644
index 0000000..01d578a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/cast11.C
@@ -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));
+}

Reply via email to