diff mbox

c++/78771 ICE with inheriting ctor

Message ID 98daf7d1-8d37-6f96-8e91-a5310bb07657@acm.org
State New
Headers show

Commit Message

Nathan Sidwell Dec. 19, 2016, 1:09 p.m. UTC
Jason,
this patch fixes 78771, were an assert fires due to recursive 
instantiation of an inheriting ctor.  Normally when a recursive 
instantiation is needed, we've already constructed and registered the 
declaration, so simply return it.  For ctors though we need to construct 
the clones after we've instantiated the the master pattern (later in 
instantiate_template_1).  Hence any recursive instantiation of a cloned 
fn will barf, as we do.

Now, with an inherited ctor we have to deduce its exception spec and 
deletedness (deduce_inheriting_ctor).  That's fine, until one gets the 
perverse testcase here.  In figuring out what Middle ctor is needed by 
Middle(0), we end up trying to instantiate Derived::Derived (int) to see 
if Middle::Middle (Derived) is a viable candidate.  And that's the 
recursion, as Derived::Derived inherits from Middle::Middle.

Fixed by checking if the cloned instantiations actually exist before 
looking for them.  I think the only case this can occur is when SPEC is 
an inherited ctor, hence the assert.  Also, I don't think this can get 
us the wrong exept spec and deletedness -- it will be other (member) 
ctors that could change it, and we reconstruct the clones later anyway 
in the usual path.

(I tried creating the clones earlier, immediately after construction and 
registering the main function, but that didn't work)

ok?

nathan
-- 
Nathan Sidwell

Comments

Jason Merrill Jan. 4, 2017, 5:53 a.m. UTC | #1
On 12/19/2016 08:09 AM, Nathan Sidwell wrote:
> this patch fixes 78771, were an assert fires due to recursive

> instantiation of an inheriting ctor.  Normally when a recursive

> instantiation is needed, we've already constructed and registered the

> declaration, so simply return it.  For ctors though we need to construct

> the clones after we've instantiated the the master pattern (later in

> instantiate_template_1).  Hence any recursive instantiation of a cloned

> fn will barf, as we do.

>

> Now, with an inherited ctor we have to deduce its exception spec and

> deletedness (deduce_inheriting_ctor).  That's fine, until one gets the

> perverse testcase here.  In figuring out what Middle ctor is needed by

> Middle(0), we end up trying to instantiate Derived::Derived (int) to see

> if Middle::Middle (Derived) is a viable candidate.


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.

Jason
diff mbox

Patch

2016-12-19  Nathan Sidwell  <nathan@acm.org>

	PR c++/78771
	* pt.c (instantiate_template_1): Check for recursive instantiation
	of inheriting constructor.

	PR c++/78771
	* g++.dg/cpp0x/pr78771.C: New.

Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 243746)
+++ cp/pt.c	(working copy)
@@ -17717,10 +17717,22 @@  instantiate_template_1 (tree tmpl, tree
       if (spec == error_mark_node)
 	return error_mark_node;
 
+      /* If this is an inherited ctor, we can recursively clone it
+	 when deducing the validity of the ctor.  But we won't have
+	 cloned the function yet, so do it now.  We'll redo this
+	 later, but any recursive information learnt here can't
+	 change the validity.  */
+      if (!TREE_CHAIN (spec))
+	{
+	  gcc_assert (DECL_INHERITED_CTOR (spec));
+	  clone_function_decl (spec, /*update_method_vec_p=*/0);
+	}
+
       /* Look for the clone.  */
       FOR_EACH_CLONE (clone, spec)
 	if (DECL_NAME (clone) == DECL_NAME (tmpl))
 	  return clone;
+
       /* We should always have found the clone by now.  */
       gcc_unreachable ();
       return NULL_TREE;
Index: testsuite/g++.dg/cpp0x/pr78771.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr78771.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/pr78771.C	(working copy)
@@ -0,0 +1,27 @@ 
+// PR c++/78771
+// { dg-do compile { target c++11 } }
+
+// 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) {}