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));
+}