Skip to content

Commit

Permalink
c++: ambiguous call not diagnosed after DR2352 [PR97296]
Browse files Browse the repository at this point in the history
DR 2352 changed the definitions of reference-related (so that it uses
"similar type" instead of "same type") and of reference-compatible (use
a standard conversion sequence).  That means that reference-related is
now more broad, which means that we will be binding more things directly.

The original patch for DR 2352 caused some problems, which were fixed in
r276251 by creating a "fake" ck_qual in direct_reference_binding, so
that in

  void f(int *); // #1
  void f(const int * const &); // #2
  int *x;
  int main()
  {
    f(x); // call #1
  }

we call #1.  The extra ck_qual in #2 causes compare_ics to select #1,
which is a better match for "int *" because then we don't have to do
a qualification conversion.

Let's turn to the problem in this PR.  We have

  void f(const int * const &); // #1
  void f(const int *); // #2
  int *x;
  int main()
  {
    f(x);
  }

We arrive in compare_ics to decide which one is better. The ICS for #1
looks like

    ck_ref_bind      <-    ck_qual         <-   ck_identity
  const int *const &     const int *const         int *

and the ICS for #2 is

    ck_qual     <-  ck_rvalue   <-  ck_identity
  const int *          int *           int *

We strip the reference and then comp_cv_qual_signature when comparing two
ck_quals sees that "const int *" is a proper subset of "const int *const"
and we return -1.  But that's wrong; presumably the top-level "const"
should be ignored and the call should be ambiguous.  This patch adjust
the type of the "fake" ck_qual so that this problem doesn't arise.

	PR c++/97296

gcc/cp/ChangeLog:

	* call.cc (direct_reference_binding): strip_top_quals when creating
	a ck_qual.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/ref-bind4.C: Add dg-error.
	* g++.dg/cpp0x/ref-bind8.C: New test.
  • Loading branch information
mpolacek committed Apr 13, 2022
1 parent 9645279 commit 85ae54e
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 3 deletions.
15 changes: 13 additions & 2 deletions gcc/cp/call.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1680,8 +1680,19 @@ direct_reference_binding (tree type, conversion *conv)
because the types "int *" and "const int *const" are
reference-related and we were binding both directly and they
had the same rank. To break it up, we add a ck_qual under the
ck_ref_bind so that conversion sequence ranking chooses #1. */
conv = build_conv (ck_qual, t, conv);
ck_ref_bind so that conversion sequence ranking chooses #1.

We strip_top_quals here which is also what standard_conversion
does. Failure to do so would confuse comp_cv_qual_signature
into thinking that in

void f(const int * const &); // #1
void f(const int *); // #2
int *x;
f(x);

#2 is a better match than #1 even though they're ambiguous (97296). */
conv = build_conv (ck_qual, strip_top_quals (t), conv);

return build_conv (ck_ref_bind, type, conv);
}
Expand Down
2 changes: 1 addition & 1 deletion gcc/testsuite/g++.dg/cpp0x/ref-bind4.C
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ g (int *p, const int *pc, const int **q)
similar types T1 and T2 (_conv.qual_), respectively, and the cv-
qualification signature of type T1 is a proper subset of the cv-
qualification signature of type T2 */
f8 (q);
f8 (q); // { dg-error "call of overloaded" }
f9 (q);
}
10 changes: 10 additions & 0 deletions gcc/testsuite/g++.dg/cpp0x/ref-bind8.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// PR c++/97296
// { dg-do compile }

void f(const int * const &);
void f(const int *);
int *x;
int main()
{
f(x); // { dg-error "call of overloaded" }
}

0 comments on commit 85ae54e

Please sign in to comment.