In committee review of the rule to restore effective hiding in overload resolution between a base constructor with a default argument and a derived constructor without, it was observed that what we were doing doesn't properly handle the case where both constructors are from bases, just one more derived. This patch fixes that.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit ae6d87429550f4354730e17113d4b0fb32d96571 Author: Jason Merrill <ja...@redhat.com> Date: Fri Mar 3 14:47:09 2017 -1000 Core issues 2273 and 2277 * call.c (joust): Adjust using-declaration tiebreaker to handle the intermediate base case. * method.c (strip_inheriting_ctors): Just return the argument if !flag_new_inheriting_ctors. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index dc629b96..5afec4f 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -9735,20 +9735,26 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, } } - /* or, if not that, F2 is from a using-declaration, F1 is not, and the - conversion sequences are equivalent. - (proposed in http://lists.isocpp.org/core/2016/10/1142.php) */ + /* F1 is a member of a class D, F2 is a member of a base class B of D, and + for all arguments the corresponding parameters of F1 and F2 have the same + type (CWG 2273/2277). */ if (DECL_P (cand1->fn) && DECL_CLASS_SCOPE_P (cand1->fn) && !DECL_CONV_FN_P (cand1->fn) && DECL_P (cand2->fn) && DECL_CLASS_SCOPE_P (cand2->fn) && !DECL_CONV_FN_P (cand2->fn)) { - bool used1 = (DECL_INHERITED_CTOR (cand1->fn) - || (BINFO_TYPE (cand1->access_path) - != DECL_CONTEXT (cand1->fn))); - bool used2 = (DECL_INHERITED_CTOR (cand2->fn) - || (BINFO_TYPE (cand2->access_path) - != DECL_CONTEXT (cand2->fn))); + tree base1 = DECL_CONTEXT (strip_inheriting_ctors (cand1->fn)); + tree base2 = DECL_CONTEXT (strip_inheriting_ctors (cand2->fn)); + + bool used1 = false; + bool used2 = false; + if (base1 == base2) + /* No difference. */; + else if (DERIVED_FROM_P (base1, base2)) + used1 = true; + else if (DERIVED_FROM_P (base2, base1)) + used2 = true; + if (int diff = used2 - used1) { for (i = 0; i < len; ++i) diff --git a/gcc/cp/method.c b/gcc/cp/method.c index beb0a24..f6024cd 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -498,7 +498,8 @@ forward_parm (tree parm) tree strip_inheriting_ctors (tree dfn) { - gcc_assert (flag_new_inheriting_ctors); + if (!flag_new_inheriting_ctors) + return dfn; tree fn = dfn; while (tree inh = DECL_INHERITED_CTOR (fn)) { diff --git a/gcc/testsuite/g++.dg/overload/using5.C b/gcc/testsuite/g++.dg/overload/using5.C new file mode 100644 index 0000000..ad17c78 --- /dev/null +++ b/gcc/testsuite/g++.dg/overload/using5.C @@ -0,0 +1,28 @@ +// Core issues 2273, 2277 +// { dg-do compile { target c++11 } } + +struct A +{ + A(int, int = 0); + static void f(int = 0); +}; + +struct B: A +{ + using A::A; + B(int); + + using A::f; + static void f(); +}; + +struct C: B { + using B::B; + using B::f; +}; + +int main() +{ + C c (42); + c.f(); +}