[PATCH] Fix PR c++/70610 (wrong overload resolution during template processing)
Patrick Palka
patrick@parcs.ath.cx
Mon Apr 11 21:20:00 GMT 2016
The gist of the issue is that with -std=c++03 or earlier a
NON_DEPENDENT_EXPR is considered to always be an lvalue according to
lvalue_kind(). This causes overload resolution to malfunction during
template processing because it sometimes chooses an overload that
expects an lvalue argument even though the expression underlying the
NON_DEPENDENT_EXPR is not an lvalue. My patch for PR c++/21802
exacerbated this issue by having operator overload resolution get
performed only once, at template processing time (where we see
NON_DEPENDENT_EXPRs), instead of twice, at template processing time and
then at instantiation time (where we don't see NON_DEPENDENT_EXPRs).
The issue though is not restricted to operator overloads, it also
manifests itself in regular function overloads (see pr70610-3.C which
currently fails with an ambiguous overload error).
>From what I can tell the special casing done in lvalue_kind() for older
cxx_dialects is no longer necessary, so this patch removes it to have
lvalue_kind() unconditionally recurse into NON_DEPENDENT_EXPRs. This
however caused a c++98 regression in g++.dg/template/lvalue2.C which is
fixed by removing the guard against cxx_dialect in
build_x_conditional_expr which also no longer seems necessary. Although
I haven't looked too carefully...
Bootstrapped + regtested on x86_64-pc-linux-gnu, does this look OK to
commit?
gcc/cp/ChangeLog:
PR c++/70610
* tree.c (lvalue_kind) [NON_DEPENDENT_EXPR]: Unconditionally
recurse into it.
* typeck.c (build_x_conditional_expr): Unconditionally remember
that the result is an lvalue or xvalue.
gcc/testsuite/ChangeLog:
PR c++/70610
* g++.dg/template/pr70610.C: New test.
* g++.dg/template/pr70610-2.C: New test.
* g++.dg/template/pr70610-3.C: New test.
* g++.dg/template/pr70610-4.C: New test.
---
gcc/cp/tree.c | 8 +-------
gcc/cp/typeck.c | 6 ++----
gcc/testsuite/g++.dg/template/pr70610-2.C | 21 +++++++++++++++++++++
gcc/testsuite/g++.dg/template/pr70610-3.C | 21 +++++++++++++++++++++
gcc/testsuite/g++.dg/template/pr70610-4.C | 19 +++++++++++++++++++
gcc/testsuite/g++.dg/template/pr70610.C | 21 +++++++++++++++++++++
6 files changed, 85 insertions(+), 11 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/template/pr70610-2.C
create mode 100644 gcc/testsuite/g++.dg/template/pr70610-3.C
create mode 100644 gcc/testsuite/g++.dg/template/pr70610-4.C
create mode 100644 gcc/testsuite/g++.dg/template/pr70610.C
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 5d9de34..df2981f 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -224,13 +224,7 @@ lvalue_kind (const_tree ref)
return lvalue_kind (BASELINK_FUNCTIONS (CONST_CAST_TREE (ref)));
case NON_DEPENDENT_EXPR:
- /* We just return clk_ordinary for NON_DEPENDENT_EXPR in C++98, but
- in C++11 lvalues don't bind to rvalue references, so we need to
- work harder to avoid bogus errors (c++/44870). */
- if (cxx_dialect < cxx11)
- return clk_ordinary;
- else
- return lvalue_kind (TREE_OPERAND (ref, 0));
+ return lvalue_kind (TREE_OPERAND (ref, 0));
default:
if (!TREE_TYPE (ref))
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 4dc1b55..a62bae4 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -6275,10 +6275,8 @@ build_x_conditional_expr (location_t loc, tree ifexp, tree op1, tree op2,
{
tree min = build_min_non_dep (COND_EXPR, expr,
orig_ifexp, orig_op1, orig_op2);
- /* In C++11, remember that the result is an lvalue or xvalue.
- In C++98, lvalue_kind can just assume lvalue in a template. */
- if (cxx_dialect >= cxx11
- && lvalue_or_rvalue_with_address_p (expr)
+ /* Remember that the result is an lvalue or xvalue. */
+ if (lvalue_or_rvalue_with_address_p (expr)
&& !lvalue_or_rvalue_with_address_p (min))
TREE_TYPE (min) = cp_build_reference_type (TREE_TYPE (min),
!real_lvalue_p (expr));
diff --git a/gcc/testsuite/g++.dg/template/pr70610-2.C b/gcc/testsuite/g++.dg/template/pr70610-2.C
new file mode 100644
index 0000000..3368a5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/pr70610-2.C
@@ -0,0 +1,21 @@
+// PR c++/70610
+// { dg-do link }
+
+struct A { };
+
+void operator+ (const A &, A &);
+void operator+ (A &, const A &);
+void operator+ (const A &, const A &) { }
+
+template <typename T>
+void
+foo ()
+{
+ A () + A ();
+}
+
+int
+main ()
+{
+ foo<int> ();
+}
diff --git a/gcc/testsuite/g++.dg/template/pr70610-3.C b/gcc/testsuite/g++.dg/template/pr70610-3.C
new file mode 100644
index 0000000..4be458c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/pr70610-3.C
@@ -0,0 +1,21 @@
+// PR c++/70610
+// { dg-do link }
+
+void bar (const int &, int &);
+void bar (int &, const int &);
+void bar (const int &, const int &) { }
+
+int a, b;
+
+template <typename T>
+void
+foo ()
+{
+ bar (a + 1, b + 2);
+}
+
+int
+main ()
+{
+ foo<int> ();
+}
diff --git a/gcc/testsuite/g++.dg/template/pr70610-4.C b/gcc/testsuite/g++.dg/template/pr70610-4.C
new file mode 100644
index 0000000..127abdc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/pr70610-4.C
@@ -0,0 +1,19 @@
+// PR c++/70610
+// { dg-do link }
+
+struct A { void operator+ (const A &) { }; };
+
+void operator+ (const A &, A &);
+
+template <typename T>
+void
+foo ()
+{
+ A () + A ();
+}
+
+int
+main ()
+{
+ foo<int> ();
+}
diff --git a/gcc/testsuite/g++.dg/template/pr70610.C b/gcc/testsuite/g++.dg/template/pr70610.C
new file mode 100644
index 0000000..c7dde1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/pr70610.C
@@ -0,0 +1,21 @@
+// PR c++/70610
+// { dg-do link }
+
+struct A { };
+
+void operator+ (A &);
+void operator+ (const A &) { }
+
+
+template <typename T>
+void
+foo ()
+{
+ +A ();
+}
+
+int
+main ()
+{
+ foo<int> ();
+}
--
2.8.1.135.ga04ac66
More information about the Gcc-patches
mailing list