RFA (tree-inline): PATCH for C++ inheriting constructors overhaul

Jason Merrill jason@redhat.com
Mon Oct 31 15:45:00 GMT 2016


wg21.link/p0136 significantly changes the specification of C++11
inheriting constructors so that they become an implementation detail
rather than a language-level construct; instead, overload resolution
and such are done on the constructor from the base, and the artificial
constructor in the derived class comes in only later.  As a result,
several things that worked poorly with the old specification work much
better.  But this changes the representation as well; as a result, the
mangled name of the artificial inherited constructor is changing.

This proposal is part of C++17, but it is specified as a defect report
against C++11 and C++14 as well, so the new behavior affects those
modes as well.  The change can be controlled with
-fno-new-inheriting-ctors, and it is also disabled by default with
-fabi-version=10 or below.

One subtlety with the new scheme is that base constructor clones of an
inheriting constructor that inherits from a virtual base don't get the
inherited parameters, since they won't actually call the constructor
for the virtual base; only the complete constructor clone does that.

For the cloning code to handle omitted inherited parms, I needed to
change copy_tree_body_r to immediately optimize away a COND_EXPR with
a constant condition, as the non-taken branch would try to pass the
omitted parameters to the virtual base constructor.

Is the tree-inline.c patch OK for trunk?
-------------- next part --------------
commit 1375d880435fc21023a812ad17da209e44526b07
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Oct 25 23:53:51 2016 -0400

            Implement P0136R1, Rewording inheriting constructors.
    
    gcc/c-family/
            * c.opt (-fnew-inheriting-ctors): New.
            * c-opts.c: Default to on for ABI 11+.
    gcc/cp/
            * call.c (enum rejection_reason_code): Add rr_inherited_ctor.
            (inherited_ctor_rejection): New.
            (add_function_candidate): Reject inherited ctors for copying.
            (enforce_access): Use strip_inheriting_ctors.
            (print_z_candidate): Likewise.  Handle rr_inherited_ctor.
            (convert_like_real): Avoid copying inheriting ctor parameters.
            (build_over_call): Likewise.  A base ctor inheriting from vbase
            has no parms.  Sorry about varargs.
            (joust): A local constructor beats inherited with the same convs.
            * class.c (add_method): Handle hiding inheriting ctors.
            (one_inherited_ctor): Handle new semantics.
            (add_implicitly_declared_members): Pass using_decl down.
            (build_clone): A base ctor inheriting from vbase has no parms.
            * cp-tree.h (DECL_INHERITED_CTOR): Store this instead of the base.
            (SET_DECL_INHERITED_CTOR): Likewise.
            (DECL_INHERITED_CTOR_BASE): Adjust.
            * constexpr.c: Adjust.
            * error.c (dump_function_decl): Decorate inheriting ctors.
            * init.c (emit_mem_initializers): Suppress access control in
            inheriting ctor.
            * mangle.c (write_special_name_constructor): Handle new inheriting
            ctor mangling.
            * method.c (strip_inheriting_ctors, inherited_ctor_binfo)
            (ctor_omit_inherited_parms, binfo_inherited_from): New.
            (synthesized_method_walk): Use binfo_inherited_from.  Suppress
            access control in inheriting ctor.
            (deduce_inheriting_ctor): Deleted if ambiguous ctor inheritance.
            (maybe_explain_implicit_delete): Explain ambigous ctor inheritance.
            (add_one_base_init, do_build_copy_constructor): Adjust.
            (locate_fn_flags, explain_implicit_non_constexpr): Adjust.
            (implicitly_declare_fn): Adjust.
            (get_inherited_ctor): Remove.
            * name-lookup.c (do_class_using_decl): Check for indirect ctor
            inheritance.
            * optimize.c (cdtor_comdat_group): Adjust for new mangling.
            (maybe_clone_body): Handle omitted parms in base clone.
            (maybe_thunk_body): Don't thunk if base clone omits parms.
            * pt.c (tsubst_decl): Adjust.
            (instantiate_template_1): Suppress access control in inheriting
            ctor.
            (fn_type_unification): Do deduction with inherited ctor.
            * tree.c (special_function_p): Adjust.
    gcc/
            * tree-inline.c (copy_tree_body_r): Only copy the taken branch of
            a COND_EXPR with constant condition.
    libiberty/
            * cp-demangle.c (d_ctor_dtor_name): Handle inheriting constructor.

diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index c399307..969b05c 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -914,6 +914,12 @@ c_common_post_options (const char **pfilename)
   if (flag_abi_version == 0)
     flag_abi_version = 11;
 
+  /* By default, enable the new inheriting constructor semantics along with ABI
+     11.  New and old should coexist fine, but it is a change in what
+     artificial symbols are generated.  */
+  if (!global_options_set.x_flag_new_inheriting_ctors)
+    flag_new_inheriting_ctors = abi_version_at_least (11);
+
   if (cxx_dialect >= cxx11)
     {
       /* If we're allowing C++0x constructs, don't warn about C++98
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 458d453..575f1b7 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1362,6 +1362,10 @@ fimplicit-templates
 C++ ObjC++ Var(flag_implicit_templates) Init(1)
 Emit implicit instantiations of templates.
 
+fnew-inheriting-ctors
+C++ ObjC++ Var(flag_new_inheriting_ctors) Init(1)
+Implement C++17 inheriting constructor semantics.
+
 ffriend-injection
 C++ ObjC++ Var(flag_friend_injection)
 Inject friend functions into enclosing namespace.
diff --git a/gcc/common.opt b/gcc/common.opt
index 20dbfc1..99ba0a6 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -889,7 +889,8 @@ Driver Undocumented
 ;     identity, such as ia32 calling convention attributes (stdcall, etc.)
 ;     Default in G++ 6 (set in c_common_post_options).
 ;
-; 11: The version of the ABI that corrects mangling of sizeof... expressions.
+; 11: The version of the ABI that corrects mangling of sizeof... expressions
+;     and introduces new inheriting constructor handling.
 ;     Default in G++ 7.
 ;
 ; Additional positive integers will be assigned as new versions of
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 4c19d2f..27aa7fd 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -414,6 +414,7 @@ enum rejection_reason_code {
   rr_bad_arg_conversion,
   rr_template_unification,
   rr_invalid_copy,
+  rr_inherited_ctor,
   rr_constraint_failure
 };
 
@@ -689,6 +690,13 @@ invalid_copy_with_fn_template_rejection (void)
   return r;
 }
 
+static struct rejection_reason *
+inherited_ctor_rejection (void)
+{
+  struct rejection_reason *r = alloc_rejection (rr_inherited_ctor);
+  return r;
+}
+
 // Build a constraint failure record, saving information into the
 // template_instantiation field of the rejection. If FN is not a template
 // declaration, the TMPL member is the FN declaration and TARGS is empty.
@@ -2111,6 +2119,18 @@ add_function_candidate (struct z_candidate **candidates,
 		}
 	    }
 
+	  /* Don't consider inherited constructors for initialization from an
+	     expression of the same or derived type.  */
+	  /* FIXME extend to operator=.  */
+	  if (i == 0 && len == 1
+	      && DECL_INHERITED_CTOR (fn)
+	      && reference_related_p (ctype, argtype))
+	    {
+	      viable = 0;
+	      reason = inherited_ctor_rejection ();
+	      goto out;
+	    }
+
 	  /* Core issue 899: When [copy-]initializing a temporary to be bound
 	     to the first parameter of a copy constructor (12.8) called with
 	     a single argument in the context of direct-initialization,
@@ -3393,32 +3413,40 @@ print_z_candidate (location_t loc, const char *msgstr,
   const char *msg = (msgstr == NULL
 		     ? ""
 		     : ACONCAT ((msgstr, " ", NULL)));
-  location_t cloc = location_of (candidate->fn);
+  tree fn = candidate->fn;
+  if (flag_new_inheriting_ctors)
+    fn = strip_inheriting_ctors (fn);
+  location_t cloc = location_of (fn);
 
-  if (identifier_p (candidate->fn))
+  if (identifier_p (fn))
     {
       cloc = loc;
       if (candidate->num_convs == 3)
-	inform (cloc, "%s%D(%T, %T, %T) <built-in>", msg, candidate->fn,
+	inform (cloc, "%s%D(%T, %T, %T) <built-in>", msg, fn,
 		candidate->convs[0]->type,
 		candidate->convs[1]->type,
 		candidate->convs[2]->type);
       else if (candidate->num_convs == 2)
-	inform (cloc, "%s%D(%T, %T) <built-in>", msg, candidate->fn,
+	inform (cloc, "%s%D(%T, %T) <built-in>", msg, fn,
 		candidate->convs[0]->type,
 		candidate->convs[1]->type);
       else
-	inform (cloc, "%s%D(%T) <built-in>", msg, candidate->fn,
+	inform (cloc, "%s%D(%T) <built-in>", msg, fn,
 		candidate->convs[0]->type);
     }
-  else if (TYPE_P (candidate->fn))
-    inform (cloc, "%s%T <conversion>", msg, candidate->fn);
+  else if (TYPE_P (fn))
+    inform (cloc, "%s%T <conversion>", msg, fn);
   else if (candidate->viable == -1)
-    inform (cloc, "%s%#D <near match>", msg, candidate->fn);
-  else if (DECL_DELETED_FN (candidate->fn))
-    inform (cloc, "%s%#D <deleted>", msg, candidate->fn);
+    inform (cloc, "%s%#D <near match>", msg, fn);
+  else if (DECL_DELETED_FN (fn))
+    inform (cloc, "%s%#D <deleted>", msg, fn);
   else
-    inform (cloc, "%s%#D", msg, candidate->fn);
+    inform (cloc, "%s%#D", msg, fn);
+  if (fn != candidate->fn)
+    {
+      cloc = location_of (candidate->fn);
+      inform (cloc, "  inherited here");
+    }
   /* Give the user some information about why this candidate failed.  */
   if (candidate->reason != NULL)
     {
@@ -3483,6 +3511,11 @@ print_z_candidate (location_t loc, const char *msgstr,
 	    diagnose_constraints (cloc, tmpl, args);
 	  }
 	  break;
+	case rr_inherited_ctor:
+	  inform (cloc, "  an inherited constructor is not a candidate for "
+		  "initialization from an expression of the same or derived "
+		  "type");
+	  break;
 	case rr_none:
 	default:
 	  /* This candidate didn't have any issues or we failed to
@@ -6338,10 +6371,22 @@ enforce_access (tree basetype_path, tree decl, tree diag_decl,
 {
   gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
 
+  if (flag_new_inheriting_ctors
+      && DECL_INHERITED_CTOR (decl))
+    {
+      /* 7.3.3/18: The additional constructors are accessible if they would be
+	 accessible when used to construct an object of the corresponding base
+	 class.  */
+      decl = strip_inheriting_ctors (decl);
+      basetype_path = TYPE_BINFO (DECL_CONTEXT (decl));
+    }
+
   if (!accessible_p (basetype_path, decl, true))
     {
       if (complain & tf_error)
 	{
+	  if (flag_new_inheriting_ctors)
+	    diag_decl = strip_inheriting_ctors (diag_decl);
 	  if (TREE_PRIVATE (decl))
 	    {
 	      error ("%q#D is private within this context", diag_decl);
@@ -6773,6 +6818,15 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 
       if (! MAYBE_CLASS_TYPE_P (totype))
 	return expr;
+
+      /* Don't introduce copies when passing arguments along to the inherited
+	 constructor.  */
+      if (current_function_decl
+	  && flag_new_inheriting_ctors
+	  && DECL_INHERITED_CTOR (current_function_decl)
+	  && TREE_ADDRESSABLE (totype))
+	return expr;
+
       /* Fall through.  */
     case ck_base:
       if (convs->kind == ck_base && !convs->need_temporary_p)
@@ -7800,6 +7854,29 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       check_function_arguments (input_location, TREE_TYPE (fn), nargs, fargs);
     }
 
+  if (DECL_INHERITED_CTOR (fn))
+    {
+      /* Check for passing ellipsis arguments to an inherited constructor.  We
+	 could handle this by open-coding the inherited constructor rather than
+	 defining it, but let's not bother now.  */
+      if (!cp_unevaluated_operand
+	  && cand->convs[cand->num_convs-1]->ellipsis_p)
+	{
+	  if (complain & tf_error)
+	    {
+	      sorry ("passing arguments to ellipsis of inherited constructor "
+		     "%qD", cand->fn);
+	      inform (DECL_SOURCE_LOCATION (cand->fn), "declared here");
+	    }
+	  return error_mark_node;
+	}
+
+      /* A base constructor inheriting from a virtual base doesn't get the
+	 inherited arguments, just this and __vtt.  */
+      if (ctor_omit_inherited_parms (fn))
+	nargs = 2;
+    }
+
   /* Avoid actually calling copy constructors and copy assignment operators,
      if possible.  */
 
@@ -7985,13 +8062,21 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
     }
 
   tree call = build_cxx_call (fn, nargs, argarray, complain|decltype_flag);
-  if (call != error_mark_node
-      && cand->flags & LOOKUP_LIST_INIT_CTOR)
+  if (call == error_mark_node)
+    return call;
+  if (cand->flags & LOOKUP_LIST_INIT_CTOR)
     {
       tree c = extract_call_expr (call);
       /* build_new_op_1 will clear this when appropriate.  */
       CALL_EXPR_ORDERED_ARGS (c) = true;
     }
+  if (current_function_decl
+      && flag_new_inheriting_ctors
+      && DECL_INHERITED_CTOR (current_function_decl)
+      && cand->num_convs)
+    /* Don't introduce copies when passing arguments along to the inherited
+       constructor.  */
+    CALL_FROM_THUNK_P (call) = true;
   return call;
 }
 
@@ -9539,6 +9624,34 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
 	return winner;
     }
 
+  /* 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) */
+  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)));
+      if (int diff = used2 - used1)
+	{
+	  for (i = 0; i < len; ++i)
+	    {
+	      conversion *t1 = cand1->convs[i + off1];
+	      conversion *t2 = cand2->convs[i + off2];
+	      if (!same_type_p (t1->type, t2->type))
+		break;
+	    }
+	  if (i == len)
+	    return diff;
+	}
+    }
+
   /* Check whether we can discard a builtin candidate, either because we
      have two identical ones or matching builtin and non-builtin candidates.
 
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 1a37934..c6b4ed6 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1016,7 +1016,6 @@ add_method (tree type, tree method, tree using_decl)
   bool complete_p;
   bool insert_p = false;
   tree current_fns;
-  tree fns;
 
   if (method == error_mark_node)
     return false;
@@ -1083,8 +1082,9 @@ add_method (tree type, tree method, tree using_decl)
   current_fns = insert_p ? NULL_TREE : (*method_vec)[slot];
 
   /* Check to see if we've already got this method.  */
-  for (fns = current_fns; fns; fns = OVL_NEXT (fns))
+  for (tree *p = &current_fns; *p; )
     {
+      tree fns = *p;
       tree fn = OVL_CURRENT (fns);
       tree fn_type;
       tree method_type;
@@ -1092,12 +1092,14 @@ add_method (tree type, tree method, tree using_decl)
       tree parms2;
 
       if (TREE_CODE (fn) != TREE_CODE (method))
-	continue;
+	goto cont;
 
       /* Two using-declarations can coexist, we'll complain about ambiguity in
 	 overload resolution.  */
-      if (using_decl && TREE_CODE (fns) == OVERLOAD && OVL_USED (fns))
-	continue;
+      if (using_decl && TREE_CODE (fns) == OVERLOAD && OVL_USED (fns)
+	  /* Except handle inherited constructors specially.  */
+	  && ! DECL_CONSTRUCTOR_P (fn))
+	goto cont;
 
       /* [over.load] Member function declarations with the
 	 same name and the same parameter types cannot be
@@ -1131,7 +1133,7 @@ add_method (tree type, tree method, tree using_decl)
 	      == FUNCTION_REF_QUALIFIED (method_type))
 	  && (type_memfn_quals (fn_type) != type_memfn_quals (method_type)
 	      || type_memfn_rqual (fn_type) != type_memfn_rqual (method_type)))
-	  continue;
+	  goto cont;
 
       /* For templates, the return type and template parameters
 	 must be identical.  */
@@ -1140,7 +1142,7 @@ add_method (tree type, tree method, tree using_decl)
 			    TREE_TYPE (method_type))
 	      || !comp_template_parms (DECL_TEMPLATE_PARMS (fn),
 				       DECL_TEMPLATE_PARMS (method))))
-	continue;
+	goto cont;
 
       if (! DECL_STATIC_FUNCTION_P (fn))
 	parms1 = TREE_CHAIN (parms1);
@@ -1178,18 +1180,38 @@ add_method (tree type, tree method, tree using_decl)
 		    mangle_decl (method);
 		}
 	      cgraph_node::record_function_versions (fn, method);
-	      continue;
+	      goto cont;
 	    }
-	  if (DECL_INHERITED_CTOR_BASE (method))
+	  if (DECL_INHERITED_CTOR (method))
 	    {
-	      if (DECL_INHERITED_CTOR_BASE (fn))
+	      if (DECL_INHERITED_CTOR (fn))
 		{
+		  tree basem = DECL_INHERITED_CTOR_BASE (method);
+		  tree basef = DECL_INHERITED_CTOR_BASE (fn);
+		  if (flag_new_inheriting_ctors)
+		    {
+		      if (basem == basef)
+			{
+			  /* Inheriting the same constructor along different
+			     paths, combine them.  */
+			  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;
+			}
+		      else
+			/* Inherited ctors can coexist until overload
+			   resolution.  */
+			goto cont;
+		    }
 		  error_at (DECL_SOURCE_LOCATION (method),
-			    "%q#D inherited from %qT", method,
-			    DECL_INHERITED_CTOR_BASE (method));
+			    "%q#D", method);
 		  error_at (DECL_SOURCE_LOCATION (fn),
 			    "conflicts with version inherited from %qT",
-			    DECL_INHERITED_CTOR_BASE (fn));
+			    basef);
 		}
 	      /* Otherwise defer to the other function.  */
 	      return false;
@@ -1200,6 +1222,13 @@ add_method (tree type, tree method, tree using_decl)
 		/* Defer to the local function.  */
 		return false;
 	    }
+	  else if (flag_new_inheriting_ctors
+		   && DECL_INHERITED_CTOR (fn))
+	    {
+	      /* Hide the inherited constructor.  */
+	      *p = OVL_NEXT (fns);
+	      continue;
+	    }
 	  else
 	    {
 	      error ("%q+#D cannot be overloaded", method);
@@ -1212,6 +1241,12 @@ add_method (tree type, tree method, tree using_decl)
 	     will crash while processing the definitions.  */
 	  return false;
 	}
+
+    cont:
+      if (TREE_CODE (fns) == OVERLOAD)
+	p = &OVL_CHAIN (fns);
+      else
+	break;
     }
 
   /* A class should never have more than one destructor.  */
@@ -3308,10 +3343,19 @@ one_inheriting_sig (tree t, tree ctor, tree *parms, int nparms)
    constructor CTOR.  */
 
 static void
-one_inherited_ctor (tree ctor, tree t)
+one_inherited_ctor (tree ctor, tree t, tree using_decl)
 {
   tree parms = FUNCTION_FIRST_USER_PARMTYPE (ctor);
 
+  if (flag_new_inheriting_ctors)
+    {
+      ctor = implicitly_declare_fn (sfk_inheriting_constructor,
+				    t, /*const*/false, ctor, parms);
+      add_method (t, ctor, using_decl);
+      TYPE_HAS_USER_CONSTRUCTOR (t) = true;
+      return;
+    }
+
   tree *new_parms = XALLOCAVEC (tree, list_length (parms));
   int i = 0;
   for (; parms && parms != void_list_node; parms = TREE_CHAIN (parms))
@@ -3412,7 +3456,7 @@ add_implicitly_declared_members (tree t, tree* access_decls,
 	  input_location = DECL_SOURCE_LOCATION (using_decl);
 	  if (ctor_list)
 	    for (; ctor_list; ctor_list = OVL_NEXT (ctor_list))
-	      one_inherited_ctor (OVL_CURRENT (ctor_list), t);
+	      one_inherited_ctor (OVL_CURRENT (ctor_list), t, using_decl);
 	  *access_decls = TREE_CHAIN (*access_decls);
 	  input_location = loc;
 	}
@@ -4772,6 +4816,11 @@ build_clone (tree fn, tree name)
 	}
     }
 
+  /* A base constructor inheriting from a virtual base doesn't get the
+     arguments.  */
+  if (ctor_omit_inherited_parms (fn))
+    DECL_CHAIN (DECL_CHAIN (DECL_ARGUMENTS (clone))) = NULL_TREE;
+
   for (parms = DECL_ARGUMENTS (clone); parms; parms = DECL_CHAIN (parms))
     {
       DECL_CONTEXT (parms) = clone;
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 1ebd647..43457d2 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -171,13 +171,13 @@ is_valid_constexpr_fn (tree fun, bool complain)
 {
   bool ret = true;
 
-  if (DECL_INHERITED_CTOR_BASE (fun)
+  if (DECL_INHERITED_CTOR (fun)
       && TREE_CODE (fun) == TEMPLATE_DECL)
     {
       ret = false;
       if (complain)
 	error ("inherited constructor %qD is not constexpr",
-	       get_inherited_ctor (fun));
+	       DECL_INHERITED_CTOR (fun));
     }
   else
     {
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 45224dc..d3a5aeb 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2730,12 +2730,21 @@ struct GTY(()) lang_decl {
   (LANG_DECL_FN_CHECK (NODE)->context = (THUNKS))
 
 /* If NODE, a FUNCTION_DECL, is a C++11 inheriting constructor, then this
-   is the base it inherits from.  */
-#define DECL_INHERITED_CTOR_BASE(NODE) \
-  (DECL_CONSTRUCTOR_P (NODE) ? LANG_DECL_FN_CHECK (NODE)->context : NULL_TREE)
+   is the constructor it inherits from.  */
+#define DECL_INHERITED_CTOR(NODE) \
+  (DECL_DECLARES_FUNCTION_P (NODE) && DECL_CONSTRUCTOR_P (NODE) \
+   ? LANG_DECL_FN_CHECK (NODE)->context : NULL_TREE)
+
+/* And this is the base that constructor comes from.  */
+#define DECL_INHERITED_CTOR_BASE(NODE)			\
+  (DECL_INHERITED_CTOR (NODE)				\
+   ? DECL_CONTEXT (flag_new_inheriting_ctors		\
+		   ? strip_inheriting_ctors (NODE)	\
+		   : DECL_INHERITED_CTOR (NODE))	\
+   : NULL_TREE)
 
 /* Set the inherited base.  */
-#define SET_DECL_INHERITED_CTOR_BASE(NODE,INH) \
+#define SET_DECL_INHERITED_CTOR(NODE,INH) \
   (LANG_DECL_FN_CHECK (NODE)->context = (INH))
 
 /* Nonzero if NODE is a thunk, rather than an ordinary function.  */
@@ -6036,7 +6045,9 @@ extern tree get_copy_ctor			(tree, tsubst_flags_t);
 extern tree get_copy_assign			(tree);
 extern tree get_default_ctor			(tree);
 extern tree get_dtor				(tree, tsubst_flags_t);
-extern tree get_inherited_ctor			(tree);
+extern tree strip_inheriting_ctors		(tree);
+extern tree inherited_ctor_binfo		(tree);
+extern bool ctor_omit_inherited_parms		(tree);
 extern tree locate_ctor				(tree);
 extern tree implicitly_declare_fn               (special_function_kind, tree,
 						 bool, tree, tree);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 917a448..aa92a7e 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1617,6 +1617,13 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
             pp_cxx_requires_clause (pp, reqs);
 
       dump_substitution (pp, t, template_parms, template_args, flags);
+
+      if (tree base = DECL_INHERITED_CTOR_BASE (t))
+	{
+	  pp_cxx_ws_string (pp, "[inherited from");
+	  dump_type (pp, base, TFF_PLAIN_IDENTIFIER);
+	  pp_character (pp, ']');
+	}
     }
   else if (template_args)
     {
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 2418a9d..5eba4c3 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1117,7 +1117,7 @@ emit_mem_initializers (tree mem_inits)
     }
 
   if (DECL_DEFAULTED_FN (current_function_decl)
-      && ! DECL_INHERITED_CTOR_BASE (current_function_decl))
+      && ! DECL_INHERITED_CTOR (current_function_decl))
     flags |= LOOKUP_DEFAULTED;
 
   /* Sort the mem-initializers into the order in which the
@@ -1138,6 +1138,13 @@ emit_mem_initializers (tree mem_inits)
       if (arguments == error_mark_node)
 	continue;
 
+      /* Suppress access control when calling the inherited ctor.  */
+      bool inherited_base = (DECL_INHERITED_CTOR (current_function_decl)
+			     && flag_new_inheriting_ctors
+			     && arguments);
+      if (inherited_base)
+	push_deferring_access_checks (dk_deferred);
+
       if (arguments == NULL_TREE)
 	{
 	  /* If these initializations are taking place in a copy constructor,
@@ -1172,6 +1179,9 @@ emit_mem_initializers (tree mem_inits)
 	/* C++14 DR1658 Means we do not have to construct vbases of
 	   abstract classes.  */
 	construct_virtual_base (subobject, arguments);
+
+      if (inherited_base)
+	pop_deferring_access_checks ();
     }
   in_base_initializer = 0;
 
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index cb2f260..f3b2fe3 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -1786,18 +1786,25 @@ write_identifier (const char *identifier)
 static void
 write_special_name_constructor (const tree ctor)
 {
+  write_char ('C');
+  bool new_inh = (flag_new_inheriting_ctors
+		  && DECL_INHERITED_CTOR (ctor));
+  if (new_inh)
+    write_char ('I');
   if (DECL_BASE_CONSTRUCTOR_P (ctor))
-    write_string ("C2");
+    write_char ('2');
   /* This is the old-style "[unified]" constructor.
      In some cases, we may emit this function and call
      it from the clones in order to share code and save space.  */
   else if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor))
-    write_string ("C4");
+    write_char ('4');
   else
     {
       gcc_assert (DECL_COMPLETE_CONSTRUCTOR_P (ctor));
-      write_string ("C1");
+      write_char ('1');
     }
+  if (new_inh)
+    write_type (DECL_INHERITED_CTOR_BASE (ctor));
 }
 
 /* Handle destructor productions of non-terminal <special-name>.
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 73a670b..73d42b1 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -492,6 +492,118 @@ forward_parm (tree parm)
   return exp;
 }
 
+/* Strip all inheriting constructors, if any, to return the original
+   constructor from a (possibly indirect) base class.  */
+
+tree
+strip_inheriting_ctors (tree fn)
+{
+  gcc_assert (flag_new_inheriting_ctors);
+  while (tree inh = DECL_INHERITED_CTOR (fn))
+    {
+      inh = OVL_CURRENT (inh);
+      fn = inh;
+    }
+  return fn;
+}
+
+/* Find the binfo for the base subobject of BINFO being initialized by
+   inherited constructor FNDECL (a member of a direct base of BINFO).  */
+
+static tree inherited_ctor_binfo (tree, tree);
+static tree
+inherited_ctor_binfo_1 (tree binfo, tree fndecl)
+{
+  tree base = DECL_CONTEXT (fndecl);
+  tree base_binfo;
+  for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+    if (BINFO_TYPE (base_binfo) == base)
+      return inherited_ctor_binfo (base_binfo, fndecl);
+
+  gcc_unreachable();
+}
+
+/* Find the binfo for the base subobject of BINFO being initialized by
+   inheriting constructor FNDECL (a member of BINFO), or BINFO if FNDECL is not
+   an inheriting constructor.  */
+
+static tree
+inherited_ctor_binfo (tree binfo, tree fndecl)
+{
+  tree inh = DECL_INHERITED_CTOR (fndecl);
+  if (!inh)
+    return binfo;
+
+  tree results = NULL_TREE;
+  for (; inh; inh = OVL_NEXT (inh))
+    {
+      tree one = inherited_ctor_binfo_1 (binfo, OVL_CURRENT (inh));
+      if (!results)
+	results = one;
+      else if (one != results)
+	results = tree_cons (NULL_TREE, one, results);
+    }
+  return results;
+}
+
+/* Find the binfo for the base subobject being initialized by inheriting
+   constructor FNDECL, or NULL_TREE if FNDECL is not an inheriting
+   constructor.  */
+
+tree
+inherited_ctor_binfo (tree fndecl)
+{
+  if (!DECL_INHERITED_CTOR (fndecl))
+    return NULL_TREE;
+  tree binfo = TYPE_BINFO (DECL_CONTEXT (fndecl));
+  return inherited_ctor_binfo (binfo, fndecl);
+}
+
+/* True if we should omit all user-declared parameters from constructor FN,
+   because it is a base clone of a ctor inherited from a virtual base.  */
+
+bool
+ctor_omit_inherited_parms (tree fn)
+{
+  if (!flag_new_inheriting_ctors)
+    /* We only optimize away the parameters in the new model.  */
+    return false;
+  if (!DECL_BASE_CONSTRUCTOR_P (fn)
+      || !CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn)))
+    return false;
+  tree binfo = inherited_ctor_binfo (fn);
+  for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
+    if (BINFO_VIRTUAL_P (binfo))
+      return true;
+  return false;
+}
+
+/* True iff constructor(s) INH inherited into BINFO initializes INIT_BINFO.
+   This can be true for multiple virtual bases as well as one direct
+   non-virtual base.  */
+
+static bool
+binfo_inherited_from (tree binfo, tree init_binfo, tree inh)
+{
+  /* inh is an OVERLOAD if we inherited the same constructor along
+     multiple paths, check all of them.  */
+  for (; inh; inh = OVL_NEXT (inh))
+    {
+      tree fn = OVL_CURRENT (inh);
+      tree base = DECL_CONTEXT (fn);
+      tree base_binfo = NULL_TREE;
+      for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+	if (BINFO_TYPE (base_binfo) == base)
+	  break;
+      if (base_binfo == init_binfo
+	  || (flag_new_inheriting_ctors
+	      && binfo_inherited_from (base_binfo, init_binfo,
+				       DECL_INHERITED_CTOR (fn))))
+	return true;
+    }
+  return false;
+}
+
 /* Subroutine of do_build_copy_constructor: Add a mem-initializer for BINFO
    given the parameter or parameters PARM, possibly inherited constructor
    base INH, or move flag MOVE_P.  */
@@ -505,7 +617,7 @@ add_one_base_init (tree binfo, tree parm, bool move_p, tree inh,
     {
       /* An inheriting constructor only has a mem-initializer for
 	 the base it inherits from.  */
-      if (BINFO_TYPE (binfo) != inh)
+      if (!binfo_inherited_from (TYPE_BINFO (current_class_type), binfo, inh))
 	return member_init_list;
 
       tree *p = &init;
@@ -537,7 +649,7 @@ do_build_copy_constructor (tree fndecl)
   tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
   bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl);
   bool trivial = trivial_fn_p (fndecl);
-  tree inh = DECL_INHERITED_CTOR_BASE (fndecl);
+  tree inh = DECL_INHERITED_CTOR (fndecl);
 
   if (!inh)
     parm = convert_from_reference (parm);
@@ -901,7 +1013,7 @@ locate_fn_flags (tree type, tree name, tree argtype, int flags,
     {
       if (TREE_CODE (argtype) == TREE_LIST)
 	{
-	  for (tree elt = argtype; elt != void_list_node;
+	  for (tree elt = argtype; elt && elt != void_list_node;
 	       elt = TREE_CHAIN (elt))
 	    {
 	      tree type = TREE_VALUE (elt);
@@ -996,25 +1108,6 @@ get_copy_assign (tree type)
   return fn;
 }
 
-/* Locate the inherited constructor of constructor CTOR.  */
-
-tree
-get_inherited_ctor (tree ctor)
-{
-  gcc_assert (DECL_INHERITED_CTOR_BASE (ctor));
-
-  push_deferring_access_checks (dk_no_check);
-  tree fn = locate_fn_flags (DECL_INHERITED_CTOR_BASE (ctor),
-			     complete_ctor_identifier,
-			     FUNCTION_FIRST_USER_PARMTYPE (ctor),
-			     LOOKUP_NORMAL|LOOKUP_SPECULATIVE,
-			     tf_none);
-  pop_deferring_access_checks ();
-  if (fn == error_mark_node)
-    return NULL_TREE;
-  return fn;
-}
-
 /* walk_tree helper function for is_trivially_xible.  If *TP is a call,
    return it if it calls something other than a trivial special member
    function.  */
@@ -1330,7 +1423,7 @@ static void
 synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 			 tree *spec_p, bool *trivial_p, bool *deleted_p,
 			 bool *constexpr_p, bool diag,
-			 tree inherited_base, tree inherited_parms)
+			 tree inheriting_ctor, tree inherited_parms)
 {
   tree binfo, base_binfo, scope, fnname, rval, argtype;
   bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor;
@@ -1389,7 +1482,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
     }
 
   gcc_assert ((sfk == sfk_inheriting_constructor)
-	      == (inherited_base != NULL_TREE));
+	      == (inheriting_ctor != NULL_TREE));
 
   /* If that user-written default constructor would satisfy the
      requirements of a constexpr constructor (7.1.5), the
@@ -1465,7 +1558,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
   scope = push_scope (ctype);
 
   flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE;
-  if (!inherited_base)
+  if (!inheriting_ctor)
     flags |= LOOKUP_DEFAULTED;
 
   complain = diag ? tf_warning_or_error : tf_none;
@@ -1485,13 +1578,25 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 	/* We'll handle virtual bases below.  */
 	continue;
 
+      bool inherited_binfo = false;
+
       if (copy_arg_p)
 	argtype = build_stub_type (basetype, quals, move_p);
-      else if (basetype == inherited_base)
-	argtype = inherited_parms;
+      else if ((inherited_binfo
+		= binfo_inherited_from (binfo, base_binfo, inheriting_ctor)))
+	{
+	  /* Don't check access on the inherited constructor.  */
+	  argtype = inherited_parms;
+	  if (flag_new_inheriting_ctors)
+	    push_deferring_access_checks (dk_deferred);
+	}
       rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
-      if (inherited_base)
-	argtype = NULL_TREE;
+      if (inherited_binfo)
+	{
+	  if (flag_new_inheriting_ctors)
+	    pop_deferring_access_checks ();
+	  argtype = NULL_TREE;
+	}
 
       process_subob_fn (rval, spec_p, trivial_p, deleted_p,
 			constexpr_p, diag, basetype);
@@ -1547,9 +1652,24 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
       FOR_EACH_VEC_ELT (*vbases, i, base_binfo)
 	{
 	  tree basetype = BINFO_TYPE (base_binfo);
+	  bool inherited_binfo = false;
+
 	  if (copy_arg_p)
 	    argtype = build_stub_type (basetype, quals, move_p);
+	  else if ((inherited_binfo
+		    = binfo_inherited_from (binfo, base_binfo, inheriting_ctor)))
+	    {
+	      argtype = inherited_parms;
+	      if (flag_new_inheriting_ctors)
+		push_deferring_access_checks (dk_deferred);
+	    }
 	  rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
+	  if (inherited_binfo)
+	    {
+	      if (flag_new_inheriting_ctors)
+		pop_deferring_access_checks ();
+	      argtype = NULL_TREE;
+	    }
 
 	  process_subob_fn (rval, spec_p, trivial_p, deleted_p,
 			    constexpr_p, diag, basetype);
@@ -1598,7 +1718,7 @@ get_defaulted_eh_spec (tree decl)
   bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
   tree spec = empty_except_spec;
   synthesized_method_walk (ctype, sfk, const_p, &spec, NULL, NULL,
-			   NULL, false, DECL_INHERITED_CTOR_BASE (decl),
+			   NULL, false, DECL_INHERITED_CTOR (decl),
 			   parms);
   return spec;
 }
@@ -1657,6 +1777,17 @@ maybe_explain_implicit_delete (tree decl)
 		  decl, ctype);
 	  informed = true;
 	}
+      else if (sfk == sfk_inheriting_constructor)
+	{
+	  tree binfo = inherited_ctor_binfo (decl);
+	  if (TREE_CODE (binfo) != TREE_BINFO)
+	    {
+	      inform (DECL_SOURCE_LOCATION (decl),
+		      "%q#D inherits from multiple base subobjects",
+		      decl);
+	      informed = true;
+	    }
+	}
       if (!informed)
 	{
 	  tree parms = FUNCTION_FIRST_USER_PARMTYPE (decl);
@@ -1668,7 +1799,7 @@ maybe_explain_implicit_delete (tree decl)
 
 	  synthesized_method_walk (ctype, sfk, const_p,
 				   &raises, NULL, &deleted_p, NULL, false,
-				   DECL_INHERITED_CTOR_BASE (decl), parms);
+				   DECL_INHERITED_CTOR (decl), parms);
 	  if (deleted_p)
 	    {
 	      inform (DECL_SOURCE_LOCATION (decl),
@@ -1676,7 +1807,7 @@ maybe_explain_implicit_delete (tree decl)
 		      "definition would be ill-formed:", decl);
 	      synthesized_method_walk (ctype, sfk, const_p,
 				       NULL, NULL, NULL, NULL, true,
-				       DECL_INHERITED_CTOR_BASE (decl), parms);
+				       DECL_INHERITED_CTOR (decl), parms);
 	    }
 	  else if (!comp_except_specs
 		   (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)),
@@ -1709,7 +1840,7 @@ explain_implicit_non_constexpr (tree decl)
   synthesized_method_walk (DECL_CLASS_CONTEXT (decl),
 			   special_function_p (decl), const_p,
 			   NULL, NULL, NULL, &dummy, true,
-			   DECL_INHERITED_CTOR_BASE (decl),
+			   DECL_INHERITED_CTOR (decl),
 			   FUNCTION_FIRST_USER_PARMTYPE (decl));
 }
 
@@ -1720,14 +1851,17 @@ explain_implicit_non_constexpr (tree decl)
 void
 deduce_inheriting_ctor (tree decl)
 {
-  gcc_assert (DECL_INHERITED_CTOR_BASE (decl));
+  gcc_assert (DECL_INHERITED_CTOR (decl));
   tree spec;
   bool trivial, constexpr_, deleted;
   synthesized_method_walk (DECL_CONTEXT (decl), sfk_inheriting_constructor,
 			   false, &spec, &trivial, &deleted, &constexpr_,
 			   /*diag*/false,
-			   DECL_INHERITED_CTOR_BASE (decl),
+			   DECL_INHERITED_CTOR (decl),
 			   FUNCTION_FIRST_USER_PARMTYPE (decl));
+  if (TREE_CODE (inherited_ctor_binfo (decl)) != TREE_BINFO)
+    /* Inherited the same constructor from different base subobjects.  */
+    deleted = true;
   DECL_DELETED_FN (decl) = deleted;
   TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), spec);
 }
@@ -1828,9 +1962,6 @@ implicitly_declare_fn (special_function_kind kind, tree type,
       gcc_unreachable ();
     }
 
-  tree inherited_base = (inherited_ctor
-			 ? DECL_CONTEXT (inherited_ctor)
-			 : NULL_TREE);
   bool trivial_p = false;
 
   if (inherited_ctor && TREE_CODE (inherited_ctor) == TEMPLATE_DECL)
@@ -1846,12 +1977,12 @@ implicitly_declare_fn (special_function_kind kind, tree type,
       raises = unevaluated_noexcept_spec ();
       synthesized_method_walk (type, kind, const_p, NULL, &trivial_p,
 			       &deleted_p, &constexpr_p, false,
-			       inherited_base, inherited_parms);
+			       inherited_ctor, inherited_parms);
     }
   else
     synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
 			     &deleted_p, &constexpr_p, false,
-			     inherited_base, inherited_parms);
+			     inherited_ctor, inherited_parms);
   /* Don't bother marking a deleted constructor as constexpr.  */
   if (deleted_p)
     constexpr_p = false;
@@ -1902,7 +2033,7 @@ implicitly_declare_fn (special_function_kind kind, tree type,
     {
       tree *p = &DECL_ARGUMENTS (fn);
       int index = 1;
-      for (tree parm = inherited_parms; parm != void_list_node;
+      for (tree parm = inherited_parms; parm && parm != void_list_node;
 	   parm = TREE_CHAIN (parm))
 	{
 	  *p = cp_build_parm_decl (NULL_TREE, TREE_VALUE (parm));
@@ -1912,7 +2043,7 @@ implicitly_declare_fn (special_function_kind kind, tree type,
 	  DECL_CONTEXT (*p) = fn;
 	  p = &DECL_CHAIN (*p);
 	}
-      SET_DECL_INHERITED_CTOR_BASE (fn, inherited_base);
+      SET_DECL_INHERITED_CTOR (fn, inherited_ctor);
       DECL_NONCONVERTING_P (fn) = DECL_NONCONVERTING_P (inherited_ctor);
       /* A constructor so declared has the same access as the corresponding
 	 constructor in X.  */
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 9e84a1b..72d4fcd 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -3399,6 +3399,12 @@ do_class_using_decl (tree scope, tree name)
 	      return NULL_TREE;
 	    }
 	}
+      else if (name == ctor_identifier
+	       && BINFO_INHERITANCE_CHAIN (BINFO_INHERITANCE_CHAIN (binfo)))
+	{
+	  error ("cannot inherit constructors from indirect base %qT", scope);
+	  return NULL_TREE;
+	}
       else if (!name_dependent_p)
 	{
 	  decl = lookup_member (binfo, name, 0, false, tf_warning_or_error);
diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c
index e2032c1..b926ef7 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -166,7 +166,8 @@ cdtor_comdat_group (tree complete, tree base)
       {
 	gcc_assert (!diff_seen
 		    && idx > 0
-		    && (p[idx - 1] == 'C' || p[idx - 1] == 'D')
+		    && (p[idx - 1] == 'C' || p[idx - 1] == 'D'
+			|| p[idx - 1] == 'I')
 		    && p[idx] == '1'
 		    && q[idx] == '2');
 	grp_name[idx] = '5';
@@ -259,6 +260,11 @@ maybe_thunk_body (tree fn, bool force)
      (for non-vague linkage ctors) or the COMDAT group (otherwise).  */
 
   populate_clone_array (fn, fns);
+
+  /* Don't use thunks if the base clone omits inherited parameters.  */
+  if (ctor_omit_inherited_parms (fns[0]))
+    return 0;
+
   DECL_ABSTRACT_P (fn) = false;
   if (!DECL_WEAK (fn))
     {
@@ -490,7 +496,7 @@ maybe_clone_body (tree fn)
 	parm = DECL_CHAIN (parm);
       if (DECL_HAS_VTT_PARM_P (clone))
 	clone_parm = DECL_CHAIN (clone_parm);
-      for (; parm;
+      for (; parm && clone_parm;
 	   parm = DECL_CHAIN (parm), clone_parm = DECL_CHAIN (clone_parm))
 	/* Update this parameter.  */
 	update_cloned_parm (parm, clone_parm, first);
@@ -616,7 +622,8 @@ maybe_clone_body (tree fn)
               else
                 {
                   decl_map->put (parm, clone_parm);
-                  clone_parm = DECL_CHAIN (clone_parm);
+		  if (clone_parm)
+		    clone_parm = DECL_CHAIN (clone_parm);
                 }
             }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c916e58..8bf80b9 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12056,7 +12056,7 @@ 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_BASE (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
@@ -17658,11 +17658,16 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
   DECL_TI_ARGS (fndecl) = targ_ptr;
 
   /* Now we know the specialization, compute access previously
-     deferred.  */
-  push_access_scope (fndecl);
-  if (!perform_deferred_access_checks (complain))
-    access_ok = false;
-  pop_access_scope (fndecl);
+     deferred.  Do no access control for inheriting constructors,
+     as we already checked access for the inherited constructor.  */
+  if (!(flag_new_inheriting_ctors
+	&& DECL_INHERITED_CTOR (fndecl)))
+    {
+      push_access_scope (fndecl);
+      if (!perform_deferred_access_checks (complain))
+	access_ok = false;
+      pop_access_scope (fndecl);
+    }
   pop_deferring_access_checks ();
 
   /* If we've just instantiated the main entry point for a function,
@@ -17820,6 +17825,11 @@ fn_type_unification (tree fn,
   static int deduction_depth;
   struct pending_template *old_last_pend = last_pending_template;
   struct tinst_level *old_error_tinst = last_error_tinst_level;
+
+  tree orig_fn = fn;
+  if (flag_new_inheriting_ctors)
+    fn = strip_inheriting_ctors (fn);
+
   tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (fn);
   tree tinst;
   tree r = error_mark_node;
@@ -18108,6 +18118,11 @@ fn_type_unification (tree fn,
 	  }
     }
 
+  /* After doing deduction with the inherited constructor, actually return an
+     instantiation of the inheriting constructor.  */
+  if (orig_fn != fn)
+    decl = instantiate_template (orig_fn, targs, complain);
+
   r = decl;
 
  fail:
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 03eef00..ac15d67 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -4282,7 +4282,7 @@ special_function_p (const_tree decl)
   /* Rather than doing all this stuff with magic names, we should
      probably have a field of type `special_function_kind' in
      DECL_LANG_SPECIFIC.  */
-  if (DECL_INHERITED_CTOR_BASE (decl))
+  if (DECL_INHERITED_CTOR (decl))
     return sfk_inheriting_constructor;
   if (DECL_COPY_CONSTRUCTOR_P (decl))
     return sfk_copy_constructor;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 242eed7d..99c9b08 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -199,6 +199,7 @@ in the following sections.
 -fno-implicit-templates @gol
 -fno-implicit-inline-templates @gol
 -fno-implement-inlines  -fms-extensions @gol
+-fnew-inheriting-ctors @gol
 -fno-nonansi-builtins  -fnothrow-opt  -fno-operator-names @gol
 -fno-optional-diags  -fpermissive @gol
 -fno-pretty-templates @gol
@@ -2219,6 +2220,10 @@ Version 10, which first appeared in G++ 6.1, adds mangling of
 attributes that affect type identity, such as ia32 calling convention
 attributes (e.g. @samp{stdcall}).
 
+Version 11, which first appeared in G++ 7, corrects the mangling of
+sizeof... expressions.  It also implies
+@option{-fnew-inheriting-ctors}.
+
 See also @option{-Wabi}.
 
 @item -fabi-compat-version=@var{n}
@@ -2412,6 +2417,13 @@ errors if these functions are not inlined everywhere they are called.
 Disable Wpedantic warnings about constructs used in MFC, such as implicit
 int and getting a pointer to member function via non-standard syntax.
 
+@item -fnew-inheriting-ctors
+@opindex fnew-inheriting-ctors
+Enable the P0136 adjustment to the semantics of C++11 constructor
+inheritance.  This is part of C++17 but also considered to be a Defect
+Report against C++11 and C++14.  This flag is enabled by default
+unless @option{-fabi-version=10} or lower is specified.
+
 @item -fno-nonansi-builtins
 @opindex fno-nonansi-builtins
 Disable built-in declarations of functions that are not mandated by
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C
index ee8757f..9869110 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C
@@ -9,7 +9,7 @@ struct A
 
 struct B : A
 {
-  using A::A;			// { dg-error "A::i" }
+  using A::A;			// { dg-prune-output "A::i" }
 };
 
-constexpr B b(0);		// { dg-error "B::B" }
+constexpr B b(0);		// { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C
index 228e8ec..4fc67a4 100644
--- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C
@@ -1,4 +1,5 @@
 // { dg-do compile { target c++11 } }
+// { dg-options -fno-new-inheriting-ctors }
 
 struct A
 {
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C
index c2d33bf..a0b518c 100644
--- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C
@@ -2,6 +2,7 @@
 // constructors was a deliberate choice.
 
 // { dg-do compile { target c++11 } }
+// { dg-options -fno-new-inheriting-ctors }
 
 struct A { A(int); };
 struct B: public A
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor15a.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor15a.C
new file mode 100644
index 0000000..a9abb84
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor15a.C
@@ -0,0 +1,14 @@
+// P0136 caused us to start inheriting base copy constructors.
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct A { A(int); };
+struct B: public A
+{
+  using A::A;
+};
+
+A a (42);
+
+B b1 (24);			// inherited
+B b2 (a);			// also inherited now
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C
index e8dc84d..8cbeed6 100644
--- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C
@@ -1,4 +1,5 @@
 // { dg-do compile { target c++11 } }
+// { dg-options -fno-new-inheriting-ctors }
 
 struct B1 {
   B1(int);
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C
index 8c79c83..d0038c1 100644
--- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C
@@ -15,7 +15,7 @@ void test() {
   D1 e;		    // { dg-error "deleted" } D1 has no default constructor
 }
 struct D2 : B2 {
-  using B2::B2;	    // { dg-error "no match" } implicitly declares D2(double)
+  using B2::B2;	    // { dg-error "B1::B1" }
   B1 b;
 };
 D2 f(1.0);	    // { dg-error "deleted" } B1 has no default constructor
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C
index 676605d..5bfdd49 100644
--- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C
@@ -9,7 +9,7 @@ protected:
 
 struct B: A
 {
-  using A::A;			// { dg-message "protected" }
+  using A::A;
 };
 
 B b(42);			// { dg-error "this context" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor1.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor1.C
new file mode 100644
index 0000000..bf9df41
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor1.C
@@ -0,0 +1,5 @@
+// { dg-do compile { target c++11 } }
+
+struct A { };
+struct B: A { };
+struct C: B { using A::A; };	// { dg-error "direct" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor22.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor22.C
new file mode 100644
index 0000000..02ec58a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor22.C
@@ -0,0 +1,33 @@
+// Testcase from P0136
+// { dg-do compile { target c++11 } }
+
+struct B1 {
+  template <class... Ts>
+  B1(int, Ts...) { }
+};
+
+struct B2 {
+  B2(double) { }
+};
+
+int get();
+
+struct D1 : B1 {		// { dg-message "B1::B1" }
+  using B1::B1;  // inherits B1(int, ...)
+  int x;
+  int y = get();
+};
+
+void test() {
+  D1 d(2, 3, 4); // OK: B1 is initialized by calling B1(2, 3, 4),
+  // then d.x is default-initialized (no initialization is performed),
+  // then d.y is initialized by calling get()
+  D1 e;          // { dg-error "" } D1 has a deleted default constructor
+}
+
+struct D2 : B2 {
+  using B2::B2;			// { dg-message "B1::B1" }
+  B1 b;
+};
+
+D2 f(1.0);       // { dg-error "" } B1 has no default constructor
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C
new file mode 100644
index 0000000..0c862f7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C
@@ -0,0 +1,19 @@
+// Testcase from P0136
+// { dg-do compile { target c++11 } }
+// { dg-options "-fnew-inheriting-ctors -fdump-tree-gimple" }
+
+struct W { W(int); };
+struct V: W { using W::W; };
+struct X : virtual V { using V::V; X() = delete; };
+struct Y : X { using X::X; };
+struct Z : Y, virtual V { using Y::Y; };
+Z z(0); // OK: initialization of Y does not invoke default constructor of X
+
+// Check that we're passing this and __vtt along to the Y inheriting
+// constructor, but not the int parameter.
+// { dg-final { scan-assembler "_ZN1YCI21WEi" } }
+// { dg-final { scan-tree-dump "Y::Y ._2, _3.;" "gimple" } }
+
+// And that we *are* passing the int along to V::V.
+// { dg-final { scan-assembler "_ZN1VCI21WEi" } }
+// { dg-final { scan-tree-dump "V::V .this, _1.;" "gimple" } }
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor24.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor24.C
new file mode 100644
index 0000000..2145019
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor24.C
@@ -0,0 +1,27 @@
+// Testcase from P0136
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct A { A(int); };
+struct B : A { using A::A; };
+
+struct C1 : B { using B::B; };
+struct C2 : B { using B::B; };
+
+struct D1 : C1, C2 {
+  using C1::C1;
+  using C2::C2;
+};
+
+struct V1 : virtual B { using B::B; };
+struct V2 : virtual B { using B::B; };
+
+struct D2 : V1, V2 {
+  using V1::V1;
+  using V2::V2;
+};
+
+D1 d1(0); // { dg-error "" } ambiguous
+D2 d2(0); // OK: initializes virtual B base class, which initializes the A base
+          // class then initializes the V1 and V2 base classes as if by a
+          // defaulted default constructor
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor25.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor25.C
new file mode 100644
index 0000000..66cd2da
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor25.C
@@ -0,0 +1,9 @@
+// Testcase from P0136
+// { dg-do compile { target c++11 } }
+
+struct M { M(); M(int); };
+struct N : M { using M::M; };
+struct O : M {};
+struct P : N, O { using N::N; using O::O; };
+P p(0); // OK: use M(0) to initialize N's base class,
+        // use M() to initialize O's base class
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor26.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor26.C
new file mode 100644
index 0000000..28dc332
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor26.C
@@ -0,0 +1,17 @@
+// Testcase from P0136
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct A {
+  template<typename T> A(T, typename T::type = 0);
+  A(int);
+};
+struct B : A {
+  using A::A;
+  B(int);
+};
+B b(42L); // now calls B(int), used to call B<long>(long),
+          // which called A(int) due to substitution failure
+          // in A<long>(long).
+
+// { dg-final { scan-assembler "_ZN1BC1Ei" } }
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor27.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor27.C
new file mode 100644
index 0000000..97f2634
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor27.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+  A(int = 0);
+};
+
+struct B: A
+{
+  B();
+  using A::A;
+};
+
+B b1(1);
+B b;
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor28.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor28.C
new file mode 100644
index 0000000..55e1d8c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor28.C
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct V { V(int); };
+struct W : virtual V { using V::V; };
+struct X : virtual W, virtual V { using W::W; };
+X x(0);
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor29.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor29.C
new file mode 100644
index 0000000..97f2634
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor29.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+  A(int = 0);
+};
+
+struct B: A
+{
+  B();
+  using A::A;
+};
+
+B b1(1);
+B b;
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor30.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor30.C
new file mode 100644
index 0000000..494dd91
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor30.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+  A(double);
+};
+
+struct B: A
+{
+  B(short);
+  using A::A;
+};
+
+int main()
+{
+  B b(1);			// { dg-error "ambiguous" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor31.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor31.C
new file mode 100644
index 0000000..3ce080d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor31.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+
+struct B;
+struct A
+{
+  A(const B&, int = 0);
+};
+
+struct B: A
+{
+  using A::A;
+};
+
+extern B b;
+B b2{b};
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor32.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor32.C
new file mode 100644
index 0000000..7ce85b0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor32.C
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++11 } }
+
+struct B;
+struct A
+{
+  A(const B&, int = 0);
+};
+
+struct B: A
+{
+  using A::A;
+  B(B&);
+};
+
+extern const B b;
+B b2{b};			// { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor33.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor33.C
new file mode 100644
index 0000000..0e85207
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor33.C
@@ -0,0 +1,23 @@
+// { dg-do link { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct A
+{
+  A() { }
+  A(const A&);			// should never be called
+};
+
+struct B
+{
+  B(A) { }
+};
+
+struct C: B
+{
+  using B::B;
+};
+
+int main()
+{
+  C c{A()};
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor34.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor34.C
new file mode 100644
index 0000000..f47b2a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor34.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+class A
+{
+  A(int);
+  friend void f();
+};
+
+struct B: A
+{
+  using A::A;
+};
+
+void f()
+{
+  B b(42);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor35.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor35.C
new file mode 100644
index 0000000..87f4452
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor35.C
@@ -0,0 +1,21 @@
+// Core 1715
+// { dg-do compile { target c++11 } }
+// { dg-options -fno-new-inheriting-ctors }
+
+template<class T> struct S {
+private:
+  typedef int X;
+  friend struct B;
+};
+
+struct B {
+  template<class T> B(T, typename T::X);
+};
+
+struct D: B {
+  using B::B;			// { dg-prune-output "private" }
+};
+
+S<int> s;
+B b(s, 2); // Okay, thanks to friendship.
+D d(s, 2); // { dg-error "" } was an error before P0136
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor35a.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor35a.C
new file mode 100644
index 0000000..47f69de
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor35a.C
@@ -0,0 +1,21 @@
+// Core 1715
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+template<class T> struct S {
+private:
+  typedef int X;
+  friend struct B;
+};
+
+struct B {
+  template<class T> B(T, typename T::X);
+};
+
+struct D: B {
+  using B::B;
+};
+
+S<int> s;
+B b(s, 2); // Okay, thanks to friendship.
+D d(s, 2); // Now OK as well.
diff --git a/gcc/testsuite/g++.dg/cpp1z/using1.C b/gcc/testsuite/g++.dg/cpp1z/using1.C
new file mode 100644
index 0000000..1ed939d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/using1.C
@@ -0,0 +1,23 @@
+// Test for hiding of used base functions when all the conversion sequences are
+// equivalent, needed to avoid a regression on inherited default ctors.
+
+struct A
+{
+  void f(short,int=0);
+  void g(char,int=0);
+};
+
+struct B:A
+{
+  using A::f;
+  void f(short);
+  using A::g;
+  void g(short);
+};
+
+int main()
+{
+  B().f(1);			// OK, derived f hides base f for single arg
+  B().f(1,2);			// OK, base f can still be called with two args
+  B().g(1);			// { dg-error "" } signatures differ, ambiguous
+}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index de5e575..eee6c29 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -1241,6 +1241,28 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
 	  *walk_subtrees = 0;
 	  return NULL;
 	}
+      else if (TREE_CODE (*tp) == COND_EXPR)
+	{
+	  tree cond = TREE_OPERAND (*tp, 0);
+	  walk_tree (&cond, copy_tree_body_r, data, NULL);
+	  cond = fold (cond);
+	  if (TREE_CODE (cond) == INTEGER_CST)
+	    {
+	      /* Only copy the taken branch; for a C++ base constructor clone
+		 inherited from a virtual base, copying the other branch leads
+		 to references to parameters that were optimized away.  */
+	      tree branch = (integer_nonzerop (cond)
+			     ? TREE_OPERAND (*tp, 1)
+			     : TREE_OPERAND (*tp, 2));
+	      tree type = TREE_TYPE (*tp);
+	      if (VOID_TYPE_P (type)
+		  || type == TREE_TYPE (branch))
+		{
+		  *tp = branch;
+		  return copy_tree_body_r (tp, walk_subtrees, data);
+		}
+	    }
+	}
 
       /* Here is the "usual case".  Copy this tree node, and then
 	 tweak some special cases.  */
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index a843dc3..46382cc 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -2168,6 +2168,13 @@ d_ctor_dtor_name (struct d_info *di)
     case 'C':
       {
 	enum gnu_v3_ctor_kinds kind;
+	int inheriting = 0;
+
+	if (d_peek_next_char (di) == 'I')
+	  {
+	    inheriting = 1;
+	    d_advance (di, 1);
+	  }
 
 	switch (d_peek_next_char (di))
 	  {
@@ -2189,7 +2196,12 @@ d_ctor_dtor_name (struct d_info *di)
 	  default:
 	    return NULL;
 	  }
+
 	d_advance (di, 2);
+
+	if (inheriting)
+	  cplus_demangle_type (di);
+
 	return d_make_ctor (di, kind, di->last_name);
       }
 
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index a5a658a..a567763 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -4592,3 +4592,7 @@ __t2m05B500000000000000000_
 
 __10%0__S4_0T0T0
 %0<>::%0(%0<>)
+
+# Inheriting constructor
+_ZN1DCI11BEi
+D::B(int)


More information about the Gcc-patches mailing list