Normally, when we call an inherited constructor we determine which
base constructor it actually calls, and then use that information for
instantiating the default arguments later.  But if the base
constructor is deleted, that process breaks down: the simulated call
fails, so we don't update the base constructor, so we don't have the
template arguments, so instantiating the default arguments blows up.

A simple solution is to avoid trying to instantiate default arguments
for a deleted function; if we already know it's deleted, the call is
going to fail, we don't need to mess with argument conversions at all.
So this patch simplifies build_over_call by handling deleted functions
in one place, where we were already handling them in SFINAE context.
I'm puzzled why I didn't do this before.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit f5f375a2108ec9f1d7d76ef4cdad961a8bd72c07
Author: Jason Merrill <ja...@redhat.com>
Date:   Mon Feb 26 11:30:39 2018 -0500

            PR c++/84447 - ICE with deleted inherited ctor with default arg.
    
            * call.c (build_over_call): Handle deleted functions in one place.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 7c93c6d8290..c47befdbf7f 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7665,8 +7665,12 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
     deduce_inheriting_ctor (fn);
 
   /* Make =delete work with SFINAE.  */
-  if (DECL_DELETED_FN (fn) && !(complain & tf_error))
-    return error_mark_node;
+  if (DECL_DELETED_FN (fn))
+    {
+      if (complain & tf_error)
+       mark_used (fn);
+      return error_mark_node;
+    }
 
   if (DECL_FUNCTION_MEMBER_P (fn))
     {
@@ -7710,12 +7714,6 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
      conversions.  */
   if (flags & LOOKUP_SPECULATIVE)
     {
-      if (DECL_DELETED_FN (fn))
-       {
-         if (complain & tf_error)
-           mark_used (fn);
-         return error_mark_node;
-       }
       if (cand->viable == 1)
        return fn;
       else if (!(complain & tf_error))
@@ -8090,7 +8088,7 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
 
       /* [class.copy]: the copy constructor is implicitly defined even if
         the implementation elided its use.  */
-      if (!trivial || DECL_DELETED_FN (fn))
+      if (!trivial)
        {
          if (!mark_used (fn, complain) && !(complain & tf_error))
            return error_mark_node;
@@ -8121,8 +8119,7 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
     }
   else if (DECL_ASSIGNMENT_OPERATOR_P (fn)
           && DECL_OVERLOADED_OPERATOR_IS (fn, NOP_EXPR)
-          && trivial_fn_p (fn)
-          && !DECL_DELETED_FN (fn))
+          && trivial_fn_p (fn))
     {
       tree to = cp_stabilize_reference
        (cp_build_fold_indirect_ref (argarray[0]));
@@ -8166,8 +8163,7 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
 
       return val;
     }
-  else if (!DECL_DELETED_FN (fn)
-          && trivial_fn_p (fn))
+  else if (trivial_fn_p (fn))
     {
       if (DECL_DESTRUCTOR_P (fn))
        return fold_convert (void_type_node, argarray[0]);
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor31.C 
b/gcc/testsuite/g++.dg/cpp0x/inh-ctor31.C
new file mode 100644
index 00000000000..071f1789a3b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor31.C
@@ -0,0 +1,14 @@
+// PR c++/84447
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+  template<typename T> A(T, T = 0) = delete;
+};
+
+struct B : A
+{
+  using A::A;                  // { dg-error "deleted" }
+};
+
+B b(0);                                // { dg-error "deleted" }

Reply via email to