[prev in list] [next in list] [prev in thread] [next in thread]
List: gcc-patches
Subject: [PATCH 1/3] c++: expr-cast - C-style cast conformance [PR77465]
From: "Ed Catmur" <ed () catmur ! uk>
Date: 2021-12-30 19:57:25
Message-ID: b7066d62-7b33-4536-bf69-6f5bcf4664cf () www ! fastmail ! com
[Download RAW message or body]
PR c++/77465 - [DR909] rejected C-style cast involving casting away constness from \
result of conversion operator
PR c++/77465
gcc/cp/ChangeLog:
* call.c (tourney):
(joust):
(build_user_type_conversion_1):
(reference_binding):
(implicit_conversion_1):
(build_user_type_conversion):
(perform_overload_resolution):
(build_op_call):
(build_conditional_expr):
(build_new_op):
(build_op_subscript):
(convert_like_internal):
(build_over_call):
(build_new_method_call):
* cp-tree.h (build_user_type_conversion):
gcc/testsuite/ChangeLog:
* g++.old-deja/g++.brendan/misc17.C:
* g++.old-deja/g++.mike/p2855.C:
* g++.dg/conversion/cwg909.C: New test.
["0001-Apply-C-style-cast-rules-for-user-defined-conversion.patch" (0001-Apply-C-style-cast-rules-for-user-defined-conversion.patch)]
From 42d65d8dd984ed7f41789546cc8eeefc82cbb3fe Mon Sep 17 00:00:00 2001
From: Ed Catmur <ed@catmur.uk>
Date: Mon, 20 Dec 2021 01:06:38 +0000
Subject: [PATCH 1/3] Apply C-style cast rules for user-defined conversions
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#909
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77465
---
gcc/cp/call.c | 75 ++++++++++++-------
gcc/cp/cp-tree.h | 2 +-
gcc/testsuite/g++.dg/conversion/cwg909.C | 11 +++
.../g++.old-deja/g++.brendan/misc17.C | 4 +-
gcc/testsuite/g++.old-deja/g++.mike/p2855.C | 3 +-
5 files changed, 63 insertions(+), 32 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/conversion/cwg909.C
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index bee367f57d7..f7aad03d4d0 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -153,10 +153,11 @@ static struct obstack conversion_obstack;
static bool conversion_obstack_initialized;
struct rejection_reason;
-static struct z_candidate * tourney (struct z_candidate *, tsubst_flags_t);
+static struct z_candidate * tourney (struct z_candidate *, tsubst_flags_t,
+ bool);
static int equal_functions (tree, tree);
static int joust (struct z_candidate *, struct z_candidate *, bool,
- tsubst_flags_t);
+ tsubst_flags_t, bool);
static int compare_ics (conversion *, conversion *);
static void maybe_warn_class_memaccess (location_t, tree,
const vec<tree, va_gc> *);
@@ -167,7 +168,7 @@ static tree convert_like_with_context (conversion *, tree, tree, \
int, static void op_error (const op_location_t &, enum tree_code, enum tree_code,
tree, tree, tree, bool);
static struct z_candidate *build_user_type_conversion_1 (tree, tree, int,
- tsubst_flags_t);
+ tsubst_flags_t, bool);
static void print_z_candidate (location_t, const char *, struct z_candidate *);
static void print_z_candidates (location_t, struct z_candidate *);
static tree build_this (tree);
@@ -1880,7 +1881,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool \
c_cast_p, int flags, the reference is bound to the lvalue result of the conversion
in the second case. */
z_candidate *cand = build_user_type_conversion_1 (rto, expr, flags,
- complain);
+ complain, c_cast_p);
if (cand)
return cand->second_conv;
}
@@ -2088,7 +2089,7 @@ implicit_conversion_1 (tree to, tree from, tree expr, bool \
c_cast_p, && !CLASSTYPE_NON_AGGREGATE (complete_type (to)))
return build_aggr_conv (to, expr, flags, complain);
- cand = build_user_type_conversion_1 (to, expr, flags, complain);
+ cand = build_user_type_conversion_1 (to, expr, flags, complain, c_cast_p);
if (cand)
{
if (BRACE_ENCLOSED_INITIALIZER_P (expr)
@@ -4122,7 +4123,7 @@ add_list_candidates (tree fns, tree first_arg,
static struct z_candidate *
build_user_type_conversion_1 (tree totype, tree expr, int flags,
- tsubst_flags_t complain)
+ tsubst_flags_t complain, bool c_cast_p)
{
struct z_candidate *candidates, *cand;
tree fromtype;
@@ -4281,7 +4282,7 @@ build_user_type_conversion_1 (tree totype, tree expr, int \
flags, = implicit_conversion (totype,
rettype,
0,
- /*c_cast_p=*/false, convflags,
+ c_cast_p, convflags,
complain);
/* If LOOKUP_NO_TEMP_BIND isn't set, then this is
@@ -4359,7 +4360,7 @@ build_user_type_conversion_1 (tree totype, tree expr, int \
flags, return NULL;
}
- cand = tourney (candidates, complain);
+ cand = tourney (candidates, complain, c_cast_p);
if (cand == NULL)
{
if (complain & tf_error)
@@ -4427,13 +4428,14 @@ build_user_type_conversion_1 (tree totype, tree expr, int \
flags,
tree
build_user_type_conversion (tree totype, tree expr, int flags,
- tsubst_flags_t complain)
+ tsubst_flags_t complain, bool c_cast_p)
{
struct z_candidate *cand;
tree ret;
auto_cond_timevar tv (TV_OVERLOAD);
- cand = build_user_type_conversion_1 (totype, expr, flags, complain);
+ cand = build_user_type_conversion_1 (totype, expr, flags, complain,
+ c_cast_p);
if (cand)
{
@@ -4715,7 +4717,7 @@ perform_overload_resolution (tree fn,
*candidates = splice_viable (*candidates, false, any_viable_p);
if (*any_viable_p)
- cand = tourney (*candidates, complain);
+ cand = tourney (*candidates, complain, /*c_cast_p=*/false);
else
cand = NULL;
@@ -5086,7 +5088,7 @@ build_op_call (tree obj, vec<tree, va_gc> **args, \
tsubst_flags_t complain) }
else
{
- cand = tourney (candidates, complain);
+ cand = tourney (candidates, complain, /*c_cast_p=*/false);
if (cand == 0)
{
if (complain & tf_error)
@@ -5739,7 +5741,7 @@ build_conditional_expr (const op_location_t &loc,
arg2_type, arg3_type);
return error_mark_node;
}
- cand = tourney (candidates, complain);
+ cand = tourney (candidates, complain, /*c_cast_p=*/false);
if (!cand)
{
if (complain & tf_error)
@@ -6658,7 +6660,7 @@ build_new_op (const op_location_t &loc, enum tree_code code, \
int flags, }
else
{
- cand = tourney (candidates, complain);
+ cand = tourney (candidates, complain, /*c_cast_p=*/false);
if (cand == 0)
{
if (complain & tf_error)
@@ -6795,7 +6797,7 @@ build_new_op (const op_location_t &loc, enum tree_code code, \
int flags, {
struct candidate_warning *w;
for (w = cand->warnings; w; w = w->next)
- joust (cand, w->loser, 1, complain);
+ joust (cand, w->loser, 1, complain, /*c_cast_p=*/false);
}
/* Check for comparison of different enum types. */
@@ -7014,7 +7016,7 @@ build_op_subscript (const op_location_t &loc, tree obj,
}
else
{
- cand = tourney (candidates, complain);
+ cand = tourney (candidates, complain, /*c_cast_p=*/false);
if (cand == 0)
{
if (complain & tf_error)
@@ -7888,7 +7890,8 @@ convert_like_internal (conversion *convs, tree expr, tree fn, \
int argnum, /* We chose the surrogate function from add_conv_candidate, now we
actually need to build the conversion. */
cand = build_user_type_conversion_1 (totype, expr,
- LOOKUP_NO_CONVERSION, complain);
+ LOOKUP_NO_CONVERSION, complain,
+ c_cast_p);
tree convfn = cand->fn;
@@ -7993,7 +7996,8 @@ convert_like_internal (conversion *convs, tree expr, tree fn, \
int argnum, /* Call build_user_type_conversion again for the error. */
int flags = (convs->need_temporary_p
? LOOKUP_IMPLICIT : LOOKUP_NORMAL);
- build_user_type_conversion (totype, convs->u.expr, flags, complain);
+ build_user_type_conversion (totype, convs->u.expr, flags, complain,
+ c_cast_p);
gcc_assert (seen_error ());
maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
}
@@ -9251,7 +9255,7 @@ build_over_call (struct z_candidate *cand, int flags, \
tsubst_flags_t complain) {
struct candidate_warning *w;
for (w = cand->warnings; w; w = w->next)
- joust (cand, w->loser, 1, complain);
+ joust (cand, w->loser, 1, complain, /*c_cast_p=*/false);
}
/* Core issue 2327: P0135 doesn't say how to handle the case where the
@@ -11034,7 +11038,7 @@ build_new_method_call (tree instance, tree fns, vec<tree, \
va_gc> **args, }
else
{
- cand = tourney (candidates, complain);
+ cand = tourney (candidates, complain, /*c_cast_p=*/false);
if (cand == 0)
{
char *pretty_name;
@@ -11953,19 +11957,31 @@ cand_parms_match (z_candidate *c1, z_candidate *c2)
static int
joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
- tsubst_flags_t complain)
+ tsubst_flags_t complain, bool c_cast_p)
{
int winner = 0;
int off1 = 0, off2 = 0;
size_t i;
size_t len;
+ /* If a (C-style) conversion can be interpreted in more than one of the ways
+ listed above, the interpretation that appears first in the list is used,
+ even if a cast resulting from that interpretation is ill-formed. */
+ if (c_cast_p)
+ {
+ /* Since this is a user-defined conversion, it must be a static_cast
+ optionally followed by a const_cast. */
+ int qual1 = cand1->second_conv->kind == ck_qual;
+ int qual2 = cand2->second_conv->kind == ck_qual;
+ if (qual1 != qual2)
+ winner = qual1 ? 2 : 1;
+ /* Don't return yet, since we need to generate various warnings. */
+ }
+
/* Candidates that involve bad conversions are always worse than those
- that don't. */
- if (cand1->viable > cand2->viable)
- return 1;
- if (cand1->viable < cand2->viable)
- return -1;
+ that don't - except when performing a C-style cast. */
+ if (!c_cast_p && cand1->viable != cand2->viable)
+ return cand1->viable > cand2->viable ? 1 : -1;
/* If we have two pseudo-candidates for conversions to the same type,
or two candidates for the same function, arbitrarily pick one. */
@@ -12479,7 +12495,8 @@ tweak:
algorithm. */
static struct z_candidate *
-tourney (struct z_candidate *candidates, tsubst_flags_t complain)
+tourney (struct z_candidate *candidates, tsubst_flags_t complain,
+ bool c_cast_p)
{
struct z_candidate *champ = candidates, *challenger;
int fate;
@@ -12490,7 +12507,7 @@ tourney (struct z_candidate *candidates, tsubst_flags_t \
complain)
for (challenger = champ->next; challenger; )
{
- fate = joust (champ, challenger, 0, complain);
+ fate = joust (champ, challenger, 0, complain, c_cast_p);
if (fate == 1)
challenger = challenger->next;
else
@@ -12520,7 +12537,7 @@ tourney (struct z_candidate *candidates, tsubst_flags_t \
complain) && !(champ_compared_to_predecessor && challenger->next == champ);
challenger = challenger->next)
{
- fate = joust (champ, challenger, 0, complain);
+ fate = joust (champ, challenger, 0, complain, c_cast_p);
if (fate != 1)
return NULL;
}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5fc9e5efdab..bc1317becb0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6487,7 +6487,7 @@ extern tree extract_call_expr (tree);
extern tree build_trivial_dtor_call (tree, bool = false);
extern bool ref_conv_binds_directly_p (tree, tree);
extern tree build_user_type_conversion (tree, tree, int,
- tsubst_flags_t);
+ tsubst_flags_t, bool = false);
extern tree build_new_function_call (tree, vec<tree, va_gc> **,
tsubst_flags_t);
extern tree build_operator_new_call (tree, vec<tree, va_gc> **,
diff --git a/gcc/testsuite/g++.dg/conversion/cwg909.C \
b/gcc/testsuite/g++.dg/conversion/cwg909.C new file mode 100644
index 00000000000..c914aadc45c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/cwg909.C
@@ -0,0 +1,11 @@
+// Per CWG 909, the two casts below have the same validity and meaning, since:
+// "one possible interpretation of an old-style cast is as a static_cast followed by \
a const_cast." +
+struct S {
+ operator const int* ();
+};
+
+void f(S& s) {
+ const_cast<int*>(static_cast<const int*>(s)); // #1
+ (int*) s; // #2
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/misc17.C \
b/gcc/testsuite/g++.old-deja/g++.brendan/misc17.C index 4052664159e..c1163aba042 \
100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/misc17.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/misc17.C
@@ -32,5 +32,7 @@ FwtStdProgram::usage_if_not_complete()
{
FwtStdProgram& thisp = *this;
thisp.form("%s: error, there were unrecognized options",
- (char *) FwtErrorManager::_program);// { dg-error "" } .*
+ (char *) FwtErrorManager::_program); // OK, same as \
const_cast<char*>(static_cast<char const*>(...)) + thisp.form("%s: error, there were \
unrecognized options", + reinterpret_cast<char *>(FwtErrorManager::_program)); // \
{ dg-error "" } .* }
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/p2855.C \
b/gcc/testsuite/g++.old-deja/g++.mike/p2855.C index 48a3fe42f45..39e25b014af 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/p2855.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/p2855.C
@@ -16,6 +16,7 @@ Ctest::operator const char *() const
int main()
{
Ctest obj;
- char* temp = (char *)obj; // { dg-error "16:invalid cast" }
+ char* temp = reinterpret_cast<char *>(obj); // { dg-error "16:invalid cast" }
temp[0] = '\0';
+ char* temp2 = (char *)obj; // OK, const_cast<char *>(static_cast<char const \
*>(...)) }
--
2.30.2
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic