diff mbox

c++/78771 ICE with inheriting ctor

Message ID CADzB+2msMWH+ek1Hxag=rqe50F1Vy4xHqzk3Lh=hHTCJf4KF-Q@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill Jan. 25, 2017, 10:09 p.m. UTC
On Wed, Jan 11, 2017 at 10:53 AM, Nathan Sidwell <nathan@acm.org> wrote:
> On 01/04/2017 12:53 AM, Jason Merrill wrote:
>
>> Hmm, that seems like where the problem is.  We shouldn't try to
>> instantiate the inheriting constructor until we've already chosen the
>> base constructor; in the new model the inheriting constructor is just an
>> implementation detail.
>
> Oh what fun.  This testcase behaves differently for C++17, C++11
> -fnew-inheriting-ctors and C++11 -fno-new-inheriting-ctors compilation
> modes.
>
> Firstly, unpatched G++ is fine in C++17 mode, because:
>   /* In C++17, "If the initializer expression is a prvalue and the
>      cv-unqualified version of the source type is the same class as the
> class
>      of the destination, the initializer expression is used to initialize
> the
>      destination object."  Handle that here to avoid doing overload
>      resolution.  */
> and inside that we have:
>
>       /* FIXME P0135 doesn't say how to handle direct initialization from a
>          type with a suitable conversion operator.  Let's handle it like
>          copy-initialization, but allowing explict conversions.  */
>
> That conversion lookup short-circuits the subsequent overload resolution
> that would otherwise explode.
>
> Otherwise, with -fnew-inheriting-ctors, you are indeed correct.  There needs
> to be a call to strip_inheriting_ctors in deduce_inheriting_ctor.

That doesn't seem quite right; in deducing the inheriting ctor we are
interested in what it actually calls, so we don't want to strip.  I
was thinking about changing when we do that deduction: we shouldn't be
calling deduce_inheriting_ctor until we actually know we're calling
this inheriting ctor.  I was thinking that would mean removing the
code in fn_type_unification with the comment

  /* After doing deduction with the inherited constructor, actually
return an
     instantiation of the inheriting constructor.  */

and then looking up the inheriting constructor somehow in
build_over_call.  But that gets to be a big change.

Something smaller would be moving the call to deduce_inheriting_ctor
to build_over_call; we can get away with that because calling is the
only way to refer to a constructor. What do you think of this
approach?
commit 56586a488a27f2d5b502bd35aaec7225d0fb1d31
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jan 25 16:52:28 2017 -0500

    deduce-late

Comments

Nathan Sidwell Jan. 27, 2017, 12:50 p.m. UTC | #1
On 01/25/2017 05:09 PM, Jason Merrill wrote:

> Something smaller would be moving the call to deduce_inheriting_ctor
> to build_over_call; we can get away with that because calling is the
> only way to refer to a constructor. What do you think of this
> approach?

LGTM, thanks!

nathan
diff mbox

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index a78e1a9..99c51f3 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7581,6 +7581,11 @@  build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 	joust (cand, w->loser, 1, complain);
     }
 
+  /* OK, we're actually calling this inherited constructor; set its deletedness
+     appropriately.  */
+  if (DECL_INHERITED_CTOR (fn))
+    deduce_inheriting_ctor (fn);
+
   /* Make =delete work with SFINAE.  */
   if (DECL_DELETED_FN (fn) && !(complain & tf_error))
     return error_mark_node;
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index b7c26a1..03a9730 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1197,8 +1197,6 @@  add_method (tree type, tree method, tree using_decl)
 			  SET_DECL_INHERITED_CTOR
 			    (fn, ovl_cons (DECL_INHERITED_CTOR (method),
 					   DECL_INHERITED_CTOR (fn)));
-			  /* Adjust deletedness and such.  */
-			  deduce_inheriting_ctor (fn);
 			  /* And discard the new one.  */
 			  return false;
 			}
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 5b366f0..e80b806 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1855,6 +1855,7 @@  explain_implicit_non_constexpr (tree decl)
 void
 deduce_inheriting_ctor (tree decl)
 {
+  decl = DECL_ORIGIN (decl);
   gcc_assert (DECL_INHERITED_CTOR (decl));
   tree spec;
   bool trivial, constexpr_, deleted;
@@ -1868,6 +1869,13 @@  deduce_inheriting_ctor (tree decl)
     deleted = true;
   DECL_DELETED_FN (decl) = deleted;
   TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), spec);
+
+  tree clone;
+  FOR_EACH_CLONE (clone, decl)
+    {
+      DECL_DELETED_FN (clone) = deleted;
+      TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone), spec);
+    }
 }
 
 /* Implicitly declare the special function indicated by KIND, as a
@@ -1968,10 +1976,10 @@  implicitly_declare_fn (special_function_kind kind, tree type,
 
   bool trivial_p = false;
 
-  if (inherited_ctor && TREE_CODE (inherited_ctor) == TEMPLATE_DECL)
+  if (inherited_ctor)
     {
-      /* For an inheriting constructor template, just copy these flags from
-	 the inherited constructor template for now.  */
+      /* For an inheriting constructor, just copy these flags from the
+	 inherited constructor until deduce_inheriting_ctor.  */
       raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (inherited_ctor));
       deleted_p = DECL_DELETED_FN (inherited_ctor);
       constexpr_p = DECL_DECLARED_CONSTEXPR_P (inherited_ctor);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 537d107..c96ceed 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12358,8 +12358,6 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	    maybe_retrofit_in_chrg (r);
 	    if (DECL_CONSTRUCTOR_P (r))
 	      grok_ctor_properties (ctx, r);
-	    if (DECL_INHERITED_CTOR (r))
-	      deduce_inheriting_ctor (r);
 	    /* If this is an instantiation of a member template, clone it.
 	       If it isn't, that'll be handled by
 	       clone_constructors_and_destructors.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr78771-new.C b/gcc/testsuite/g++.dg/cpp0x/pr78771-new.C
new file mode 100644
index 0000000..f489f86
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr78771-new.C
@@ -0,0 +1,28 @@ 
+// PR c++/78771
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fnew-inheriting-ctors" }
+
+// ICE instantiating a deleted inherited ctor
+
+struct Base
+{
+  template <typename U> Base (U);
+
+  Base (int);
+};
+
+struct Derived;
+
+struct Middle : Base
+{
+  using Base::Base;
+
+  Middle (Derived);
+};
+
+struct Derived : Middle
+{
+  using Middle::Middle;
+};
+
+Middle::Middle (Derived) : Middle (0) {}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr78771-old.C b/gcc/testsuite/g++.dg/cpp0x/pr78771-old.C
new file mode 100644
index 0000000..b723b11
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr78771-old.C
@@ -0,0 +1,28 @@ 
+// PR c++/78771
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fno-new-inheriting-ctors" }
+
+// ICE instantiating a deleted inherited ctor
+
+struct Base
+{
+  template <typename U> Base (U);
+
+  Base (int);
+};
+
+struct Derived;
+
+struct Middle : Base
+{
+  using Base::Base;
+
+  Middle (Derived);
+};
+
+struct Derived : Middle
+{
+  using Middle::Middle;
+};
+
+Middle::Middle (Derived) : Middle (0) {}
diff --git a/gcc/testsuite/g++.dg/cpp1z/pr78771.C b/gcc/testsuite/g++.dg/cpp1z/pr78771.C
new file mode 100644
index 0000000..9178494
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/pr78771.C
@@ -0,0 +1,27 @@ 
+// PR c++/78771
+// { dg-options -std=c++1z }
+
+// ICE instantiating a deleted inherited ctor
+
+struct Base
+{
+  template <typename U> Base (U);
+
+  Base (int);
+};
+
+struct Derived;
+
+struct Middle : Base
+{
+  using Base::Base;
+
+  Middle (Derived);
+};
+
+struct Derived : Middle
+{
+  using Middle::Middle;
+};
+
+Middle::Middle (Derived) : Middle (0) {}