Patchwork C++ PATCH to implement C++11 inheriting constructors

login
register
mail settings
Submitter Jason Merrill
Date Oct. 15, 2012, 7:28 a.m.
Message ID <507BBB0E.5010100@redhat.com>
Download mbox | patch
Permalink /patch/191478/
State New
Headers show

Comments

Jason Merrill - Oct. 15, 2012, 7:28 a.m.
This patch implements the C++11 inheriting constructors feature: given

struct A { A(int); };
struct B { using A::A; };

the compiler defines B::B(int) that just passes its argument along to 
the A constructor.

Ville started working on this feature a while back, but got tied up with 
other things and was unable to finish it in time for 4.8, so I finished 
it up.

Tested x86_64-pc-linux-gnu, applying to trunk.

Patch

commit b1ec39978ebc71b2ebde78b4100986b444d96380
Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date:   Wed May 23 13:49:02 2012 +0300

    	Implement C++11 inheriting constructors.
    	* cp-tree.h (cpp0x_warn_str): Add CPP0X_INHERITING_CTORS.
    	(DECL_INHERITED_CTOR_BASE, SET_DECL_INHERITED_CTOR_BASE): New.
    	(special_function_kind): Add sfk_inheriting_constructor.
    	* class.c (add_method): An inheriting ctor is hidden by a
    	user-declared one.
    	(one_inheriting_sig, one_inherited_ctor): New.
    	(add_implicitly_declared_members): Handle inheriting ctors.
    	* error.c (maybe_warn_cpp0x): Handle CPP0X_INHERITING_CTORS.
    	* init.c (emit_mem_initializers): Don't set LOOKUP_DEFAULTED
    	for an inheriting constructor.
    	* method.c (type_has_trivial_fn): Handle sfk_inheriting_constructor.
    	(type_set_nontrivial_flag): Likewise.
    	(add_one_base_init): Split out from...
    	(do_build_copy_constructor): ...here.  Handle inheriting constructors.
    	(locate_fn_flags): Handle a list of arg types.
    	(synthesized_method_walk): Handle inheriting constructors.
    	(maybe_explain_implicit_delete): Likewise.
    	(deduce_inheriting_ctor): New.
    	(implicitly_declare_fn): Handle inheriting constructors.
    	* name-lookup.c (push_class_level_binding_1): An inheriting constructor
    	does not declare the base's name.
    	(do_class_using_decl): Allow inheriting constructors.
    	* pt.c (template_parms_to_args): Split from current_template_args.
    	(add_inherited_template_parms): New.
    	(tsubst_decl): Handle inheriting constructors.
    	* tree.c (special_function_p): Handle inheriting constructors.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 0e77b81..a478de8 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -132,7 +132,7 @@  static void finish_struct_methods (tree);
 static void maybe_warn_about_overly_private_class (tree);
 static int method_name_cmp (const void *, const void *);
 static int resort_method_name_cmp (const void *, const void *);
-static void add_implicitly_declared_members (tree, int, int);
+static void add_implicitly_declared_members (tree, tree*, int, int);
 static tree fixed_type_or_null (tree, int *, int *);
 static tree build_simple_base_path (tree expr, tree binfo);
 static tree build_vtbl_ref_1 (tree, tree);
@@ -1087,6 +1087,20 @@  add_method (tree type, tree method, tree using_decl)
 	      || same_type_p (TREE_TYPE (fn_type),
 			      TREE_TYPE (method_type))))
 	{
+	  if (DECL_INHERITED_CTOR_BASE (method))
+	    {
+	      if (DECL_INHERITED_CTOR_BASE (fn))
+		{
+		  error_at (DECL_SOURCE_LOCATION (method),
+			    "%q#D inherited from %qT", method,
+			    DECL_INHERITED_CTOR_BASE (method));
+		  error_at (DECL_SOURCE_LOCATION (fn),
+			    "conflicts with version inherited from %qT",
+			    DECL_INHERITED_CTOR_BASE (fn));
+		}
+	      /* Otherwise defer to the other function.  */
+	      return false;
+	    }
 	  if (using_decl)
 	    {
 	      if (DECL_CONTEXT (fn) == type)
@@ -2750,6 +2764,51 @@  declare_virt_assop_and_dtor (tree t)
 		NULL, t);
 }
 
+/* Declare the inheriting constructor for class T inherited from base
+   constructor CTOR with the parameter array PARMS of size NPARMS.  */
+
+static void
+one_inheriting_sig (tree t, tree ctor, tree *parms, int nparms)
+{
+  /* We don't declare an inheriting ctor that would be a default,
+     copy or move ctor.  */
+  if (nparms == 0
+      || (nparms == 1
+	  && TREE_CODE (parms[0]) == REFERENCE_TYPE
+	  && TYPE_MAIN_VARIANT (TREE_TYPE (parms[0])) == t))
+    return;
+  int i;
+  tree parmlist = void_list_node;
+  for (i = nparms - 1; i >= 0; i--)
+    parmlist = tree_cons (NULL_TREE, parms[i], parmlist);
+  tree fn = implicitly_declare_fn (sfk_inheriting_constructor,
+				   t, false, ctor, parmlist);
+  if (add_method (t, fn, NULL_TREE))
+    {
+      DECL_CHAIN (fn) = TYPE_METHODS (t);
+      TYPE_METHODS (t) = fn;
+    }
+}
+
+/* Declare all the inheriting constructors for class T inherited from base
+   constructor CTOR.  */
+
+static void
+one_inherited_ctor (tree ctor, tree t)
+{
+  tree parms = FUNCTION_FIRST_USER_PARMTYPE (ctor);
+
+  tree *new_parms = XALLOCAVEC (tree, list_length (parms));
+  int i = 0;
+  for (; parms && parms != void_list_node; parms = TREE_CHAIN (parms))
+    {
+      if (TREE_PURPOSE (parms))
+	one_inheriting_sig (t, ctor, new_parms, i);
+      new_parms[i++] = TREE_VALUE (parms);
+    }
+  one_inheriting_sig (t, ctor, new_parms, i);
+}
+
 /* Create default constructors, assignment operators, and so forth for
    the type indicated by T, if they are needed.  CANT_HAVE_CONST_CTOR,
    and CANT_HAVE_CONST_ASSIGNMENT are nonzero if, for whatever reason,
@@ -2758,7 +2817,7 @@  declare_virt_assop_and_dtor (tree t)
    a const reference, respectively.  */
 
 static void
-add_implicitly_declared_members (tree t,
+add_implicitly_declared_members (tree t, tree* access_decls,
 				 int cant_have_const_cctor,
 				 int cant_have_const_assignment)
 {
@@ -2826,6 +2885,26 @@  add_implicitly_declared_members (tree t,
   /* We can't be lazy about declaring functions that might override
      a virtual function from a base class.  */
   declare_virt_assop_and_dtor (t);
+
+  while (*access_decls)
+    {
+      tree using_decl = TREE_VALUE (*access_decls);
+      tree decl = USING_DECL_DECLS (using_decl);
+      if (DECL_SELF_REFERENCE_P (decl))
+	{
+	  /* declare, then remove the decl */
+	  tree ctor_list = CLASSTYPE_CONSTRUCTORS (TREE_TYPE (decl));
+	  location_t loc = input_location;
+	  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);
+	  *access_decls = TREE_CHAIN (*access_decls);
+	  input_location = loc;
+	}
+      else
+	access_decls = &TREE_CHAIN (*access_decls);
+    }
 }
 
 /* Subroutine of insert_into_classtype_sorted_fields.  Recursively
@@ -4342,7 +4421,8 @@  deduce_noexcept_on_destructor (tree dtor)
     {
       tree ctx = DECL_CONTEXT (dtor);
       tree implicit_fn = implicitly_declare_fn (sfk_destructor, ctx,
-						/*const_p=*/false);
+						/*const_p=*/false,
+						NULL, NULL);
       tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
       TREE_TYPE (dtor) = build_exception_variant (TREE_TYPE (dtor), eh_spec);
     }
@@ -5135,14 +5215,14 @@  check_bases_and_members (tree t)
     }
 
   /* Synthesize any needed methods.  */
-  add_implicitly_declared_members (t,
+  add_implicitly_declared_members (t, &access_decls,
 				   cant_have_const_ctor,
 				   no_const_asn_ref);
 
   /* Check defaulted declarations here so we have cant_have_const_ctor
      and don't need to worry about clones.  */
   for (fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn))
-    if (DECL_DEFAULTED_IN_CLASS_P (fn))
+    if (!DECL_ARTIFICIAL (fn) && DECL_DEFAULTED_IN_CLASS_P (fn))
       {
 	int copy = copy_fn_p (fn);
 	if (copy > 0)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index fdf122f..7b4277b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -420,6 +420,8 @@  typedef enum cpp0x_warn_str
   CPP0X_USER_DEFINED_LITERALS,
   /* delegating constructors */
   CPP0X_DELEGATING_CTORS,
+  /* inheriting constructors */
+  CPP0X_INHERITING_CTORS,
   /* C++11 attributes */
   CPP0X_ATTRIBUTES
 } cpp0x_warn_str;
@@ -2384,6 +2386,15 @@  struct GTY((variable_size)) lang_decl {
 #define SET_DECL_THUNKS(NODE,THUNKS) \
   (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)
+
+/* Set the inherited base.  */
+#define SET_DECL_INHERITED_CTOR_BASE(NODE,INH) \
+  (LANG_DECL_FN_CHECK (NODE)->context = (INH))
+
 /* Nonzero if NODE is a thunk, rather than an ordinary function.  */
 #define DECL_THUNK_P(NODE)			\
   (TREE_CODE (NODE) == FUNCTION_DECL		\
@@ -4142,7 +4153,8 @@  typedef enum special_function_kind {
   sfk_deleting_destructor, /* A destructor for complete objects that
 			      deletes the object after it has been
 			      destroyed.  */
-  sfk_conversion	   /* A conversion operator.  */
+  sfk_conversion,	   /* A conversion operator.  */
+  sfk_inheriting_constructor /* An inheriting constructor */
 } special_function_kind;
 
 /* The various kinds of linkage.  From [basic.link],
@@ -5323,6 +5335,7 @@  extern void use_thunk				(tree, bool);
 extern bool trivial_fn_p			(tree);
 extern bool maybe_explain_implicit_delete	(tree);
 extern void explain_implicit_non_constexpr	(tree);
+extern void deduce_inheriting_ctor		(tree);
 extern void synthesize_method			(tree);
 extern tree lazily_declare_fn			(special_function_kind,
 						 tree);
@@ -5335,7 +5348,7 @@  extern tree get_default_ctor			(tree);
 extern tree get_dtor				(tree, tsubst_flags_t);
 extern tree locate_ctor				(tree);
 extern tree implicitly_declare_fn               (special_function_kind, tree,
-						 bool);
+						 bool, tree, tree);
 
 /* In optimize.c */
 extern bool maybe_clone_body			(tree);
@@ -5370,6 +5383,7 @@  extern tree maybe_update_decl_type		(tree, tree);
 extern bool check_default_tmpl_args             (tree, tree, bool, bool, int);
 extern tree push_template_decl			(tree);
 extern tree push_template_decl_real		(tree, bool);
+extern tree add_inherited_template_parms	(tree, tree);
 extern bool redeclare_class_template		(tree, tree);
 extern tree lookup_template_class		(tree, tree, tree, tree,
 						 int, tsubst_flags_t);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 2934c9b..76f939f 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -3374,6 +3374,11 @@  maybe_warn_cpp0x (cpp0x_warn_str str)
 		 "delegating constructors "
 		 "only available with -std=c++11 or -std=gnu++11");
         break;
+      case CPP0X_INHERITING_CTORS:
+	pedwarn (input_location, 0,
+		 "inheriting constructors "
+		 "only available with -std=c++11 or -std=gnu++11");
+        break;
       case CPP0X_ATTRIBUTES:
 	pedwarn (input_location, 0,
 		 "c++11 attributes "
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 40d0ce3..0446038 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1036,7 +1036,8 @@  emit_mem_initializers (tree mem_inits)
       return;
     }
 
-  if (DECL_DEFAULTED_FN (current_function_decl))
+  if (DECL_DEFAULTED_FN (current_function_decl)
+      && ! DECL_INHERITED_CTOR_BASE (current_function_decl))
     flags |= LOOKUP_DEFAULTED;
 
   /* Sort the mem-initializers into the order in which the
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 4d44c7d..4da5cc9 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -429,6 +429,8 @@  type_has_trivial_fn (tree ctype, special_function_kind sfk)
       return !TYPE_HAS_COMPLEX_MOVE_ASSIGN (ctype);
     case sfk_destructor:
       return !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (ctype);
+    case sfk_inheriting_constructor:
+      return false;
     default:
       gcc_unreachable ();
     }
@@ -460,6 +462,7 @@  type_set_nontrivial_flag (tree ctype, special_function_kind sfk)
     case sfk_destructor:
       TYPE_HAS_NONTRIVIAL_DESTRUCTOR (ctype) = true;
       return;
+    case sfk_inheriting_constructor:
     default:
       gcc_unreachable ();
     }
@@ -478,7 +481,46 @@  trivial_fn_p (tree fn)
   return type_has_trivial_fn (DECL_CONTEXT (fn), special_function_p (fn));
 }
 
-/* Generate code for default X(X&) or X(X&&) constructor.  */
+/* 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.  */
+
+static tree
+add_one_base_init (tree binfo, tree parm, bool move_p, tree inh,
+		   tree member_init_list)
+{
+  tree init;
+  if (inh)
+    {
+      /* An inheriting constructor only has a mem-initializer for
+	 the base it inherits from.  */
+      if (BINFO_TYPE (binfo) != inh)
+	return member_init_list;
+
+      tree *p = &init;
+      init = NULL_TREE;
+      for (; parm; parm = DECL_CHAIN (parm))
+	{
+	  tree exp = convert_from_reference (parm);
+	  if (TREE_CODE (TREE_TYPE (parm)) != REFERENCE_TYPE)
+	    exp = move (exp);
+	  *p = build_tree_list (NULL_TREE, exp);
+	  p = &TREE_CHAIN (*p);
+	}
+    }
+  else
+    {
+      init = build_base_path (PLUS_EXPR, parm, binfo, 1,
+			      tf_warning_or_error);
+      if (move_p)
+	init = move (init);
+      init = build_tree_list (NULL_TREE, init);
+    }
+  return tree_cons (binfo, init, member_init_list);
+}
+
+/* Generate code for default X(X&) or X(X&&) constructor or an inheriting
+   constructor.  */
 
 static void
 do_build_copy_constructor (tree fndecl)
@@ -486,8 +528,10 @@  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);
 
-  parm = convert_from_reference (parm);
+  if (!inh)
+    parm = convert_from_reference (parm);
 
   if (trivial
       && is_empty_class (current_class_type))
@@ -516,14 +560,8 @@  do_build_copy_constructor (tree fndecl)
       for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0;
 	   VEC_iterate (tree, vbases, i, binfo); i++)
 	{
-	  init = build_base_path (PLUS_EXPR, parm, binfo, 1,
-				  tf_warning_or_error);
-	  if (move_p)
-	    init = move (init);
-	  member_init_list
-	    = tree_cons (binfo,
-			 build_tree_list (NULL_TREE, init),
-			 member_init_list);
+	  member_init_list = add_one_base_init (binfo, parm, move_p, inh,
+						member_init_list);
 	}
 
       for (binfo = TYPE_BINFO (current_class_type), i = 0;
@@ -531,15 +569,8 @@  do_build_copy_constructor (tree fndecl)
 	{
 	  if (BINFO_VIRTUAL_P (base_binfo))
 	    continue;
-
-	  init = build_base_path (PLUS_EXPR, parm, base_binfo, 1,
-				  tf_warning_or_error);
-	  if (move_p)
-	    init = move (init);
-	  member_init_list
-	    = tree_cons (base_binfo,
-			 build_tree_list (NULL_TREE, init),
-			 member_init_list);
+	  member_init_list = add_one_base_init (base_binfo, parm, move_p,
+						inh, member_init_list);
 	}
 
       for (; fields; fields = DECL_CHAIN (fields))
@@ -549,6 +580,8 @@  do_build_copy_constructor (tree fndecl)
 
 	  if (TREE_CODE (field) != FIELD_DECL)
 	    continue;
+	  if (inh)
+	    continue;
 
 	  expr_type = TREE_TYPE (field);
 	  if (DECL_NAME (field))
@@ -833,8 +866,23 @@  locate_fn_flags (tree type, tree name, tree argtype, int flags,
   args = make_tree_vector ();
   if (argtype)
     {
-      tree arg = build_stub_object (argtype);
-      VEC_quick_push (tree, args, arg);
+      if (TREE_CODE (argtype) == TREE_LIST)
+	{
+	  for (tree elt = argtype; elt != void_list_node;
+	       elt = TREE_CHAIN (elt))
+	    {
+	      tree type = TREE_VALUE (elt);
+	      if (TREE_CODE (type) != REFERENCE_TYPE)
+		type = cp_build_reference_type (type, /*rval*/true);
+	      tree arg = build_stub_object (type);
+	      VEC_safe_push (tree, gc, args, arg);
+	    }
+	}
+      else
+	{
+	  tree arg = build_stub_object (argtype);
+	  VEC_quick_push (tree, args, arg);
+	}
     }
 
   fns = lookup_fnfields (binfo, name, 0);
@@ -1110,7 +1158,8 @@  walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
 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 *no_implicit_p, bool diag)
+			 bool *constexpr_p, bool *no_implicit_p, bool diag,
+			 tree inherited_base, tree inherited_parms)
 {
   tree binfo, base_binfo, scope, fnname, rval, argtype;
   bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor;
@@ -1162,6 +1211,7 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
     case sfk_constructor:
     case sfk_move_constructor:
     case sfk_copy_constructor:
+    case sfk_inheriting_constructor:
       ctor_p = true;
       fnname = complete_ctor_identifier;
       break;
@@ -1170,6 +1220,9 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
       gcc_unreachable ();
     }
 
+  gcc_assert ((sfk == sfk_inheriting_constructor)
+	      == (inherited_base != NULL_TREE));
+
   /* If that user-written default constructor would satisfy the
      requirements of a constexpr constructor (7.1.5), the
      implicitly-defined default constructor is constexpr.  */
@@ -1181,6 +1234,7 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
     {
     case sfk_constructor:
     case sfk_destructor:
+    case sfk_inheriting_constructor:
       copy_arg_p = false;
       break;
 
@@ -1231,7 +1285,9 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 
   scope = push_scope (ctype);
 
-  flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
+  flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE;
+  if (!inherited_base)
+    flags |= LOOKUP_DEFAULTED;
 
   complain = diag ? tf_warning_or_error : tf_none;
 
@@ -1252,7 +1308,11 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 
       if (copy_arg_p)
 	argtype = build_stub_type (basetype, quals, move_p);
+      else if (basetype == inherited_base)
+	argtype = inherited_parms;
       rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
+      if (inherited_base)
+	argtype = NULL_TREE;
 
       process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
 			constexpr_p, no_implicit_p, diag, basetype);
@@ -1405,14 +1465,16 @@  maybe_explain_implicit_delete (tree decl)
 	}
       if (!informed)
 	{
-	  tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (decl));
+	  tree parms = FUNCTION_FIRST_USER_PARMTYPE (decl);
+	  tree parm_type = TREE_VALUE (parms);
 	  bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
 	  tree scope = push_scope (ctype);
 	  inform (0, "%q+#D is implicitly deleted because the default "
 		 "definition would be ill-formed:", decl);
 	  pop_scope (scope);
 	  synthesized_method_walk (ctype, sfk, const_p,
-				   NULL, NULL, NULL, NULL, NULL, true);
+				   NULL, NULL, NULL, NULL, NULL, true,
+				   DECL_INHERITED_CTOR_BASE (decl), parms);
 	}
 
       input_location = loc;
@@ -1432,7 +1494,27 @@  explain_implicit_non_constexpr (tree decl)
   bool dummy;
   synthesized_method_walk (DECL_CLASS_CONTEXT (decl),
 			   special_function_p (decl), const_p,
-			   NULL, NULL, NULL, &dummy, NULL, true);
+			   NULL, NULL, NULL, &dummy, NULL, true,
+			   NULL_TREE, NULL_TREE);
+}
+
+/* DECL is an instantiation of an inheriting constructor template.  Deduce
+   the correct exception-specification and deletedness for this particular
+   specialization.  */
+
+void
+deduce_inheriting_ctor (tree decl)
+{
+  gcc_assert (DECL_INHERITED_CTOR_BASE (decl));
+  tree spec;
+  bool trivial, constexpr_, deleted, no_implicit;
+  synthesized_method_walk (DECL_CONTEXT (decl), sfk_inheriting_constructor,
+			   false, &spec, &trivial, &deleted, &constexpr_,
+			   &no_implicit, /*diag*/false,
+			   DECL_INHERITED_CTOR_BASE (decl),
+			   FUNCTION_FIRST_USER_PARMTYPE (decl));
+  DECL_DELETED_FN (decl) = deleted;
+  TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), spec);
 }
 
 /* Implicitly declare the special function indicated by KIND, as a
@@ -1442,7 +1524,9 @@  explain_implicit_non_constexpr (tree decl)
    FUNCTION_DECL for the implicitly declared function.  */
 
 tree
-implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
+implicitly_declare_fn (special_function_kind kind, tree type,
+		       bool const_p, tree inherited_ctor,
+		       tree inherited_parms)
 {
   tree fn;
   tree parameter_types = void_list_node;
@@ -1499,6 +1583,7 @@  implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
     case sfk_copy_assignment:
     case sfk_move_constructor:
     case sfk_move_assignment:
+    case sfk_inheriting_constructor:
     {
       bool move_p;
       if (kind == sfk_copy_assignment
@@ -1510,23 +1595,44 @@  implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
       else
 	name = constructor_name (type);
 
-      if (const_p)
-	rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
+      if (kind == sfk_inheriting_constructor)
+	parameter_types = inherited_parms;
       else
-	rhs_parm_type = type;
-      move_p = (kind == sfk_move_assignment
-		|| kind == sfk_move_constructor);
-      rhs_parm_type = cp_build_reference_type (rhs_parm_type, move_p);
+	{
+	  if (const_p)
+	    rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
+	  else
+	    rhs_parm_type = type;
+	  move_p = (kind == sfk_move_assignment
+		    || kind == sfk_move_constructor);
+	  rhs_parm_type = cp_build_reference_type (rhs_parm_type, move_p);
 
-      parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types);
+	  parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types);
+	}
       break;
     }
     default:
       gcc_unreachable ();
     }
 
-  synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
-			   &deleted_p, &constexpr_p, &no_implicit_p, false);
+  tree inherited_base = (inherited_ctor
+			 ? DECL_CONTEXT (inherited_ctor)
+			 : NULL_TREE);
+  if (inherited_ctor && TREE_CODE (inherited_ctor) == TEMPLATE_DECL)
+    {
+      /* For an inheriting constructor template, just copy these flags from
+	 the inherited constructor template for now.  */
+      raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (inherited_ctor));
+      trivial_p = false;
+      deleted_p = DECL_DELETED_FN (DECL_TEMPLATE_RESULT (inherited_ctor));
+      constexpr_p
+	= DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT (inherited_ctor));
+      no_implicit_p = false;
+    }
+  else
+    synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
+			     &deleted_p, &constexpr_p, &no_implicit_p, false,
+			     inherited_base, inherited_parms);
   /* Don't bother marking a deleted constructor as constexpr.  */
   if (deleted_p)
     constexpr_p = false;
@@ -1544,9 +1650,10 @@  implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
   if (raises)
     fn_type = build_exception_variant (fn_type, raises);
   fn = build_lang_decl (FUNCTION_DECL, name, fn_type);
-  DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (TYPE_NAME (type));
+  if (kind != sfk_inheriting_constructor)
+    DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (TYPE_NAME (type));
   if (kind == sfk_constructor || kind == sfk_copy_constructor
-      || kind == sfk_move_constructor)
+      || kind == sfk_move_constructor || kind == sfk_inheriting_constructor)
     DECL_CONSTRUCTOR_P (fn) = 1;
   else if (kind == sfk_destructor)
     DECL_DESTRUCTOR_P (fn) = 1;
@@ -1575,6 +1682,27 @@  implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
       DECL_PARM_INDEX (decl) = DECL_PARM_LEVEL (decl) = 1;
       DECL_ARGUMENTS (fn) = decl;
     }
+  else if (kind == sfk_inheriting_constructor)
+    {
+      tree *p = &DECL_ARGUMENTS (fn);
+      for (tree parm = inherited_parms; parm != void_list_node;
+	   parm = TREE_CHAIN (parm))
+	{
+	  *p = cp_build_parm_decl (NULL_TREE, TREE_VALUE (parm));
+	  DECL_CONTEXT (*p) = fn;
+	  p = &DECL_CHAIN (*p);
+	}
+      SET_DECL_INHERITED_CTOR_BASE (fn, inherited_base);
+      DECL_NONCONVERTING_P (fn) = DECL_NONCONVERTING_P (inherited_ctor);
+      /* A constructor so declared has the same access as the corresponding
+	 constructor in X.  */
+      TREE_PRIVATE (fn) = TREE_PRIVATE (inherited_ctor);
+      TREE_PROTECTED (fn) = TREE_PROTECTED (inherited_ctor);
+      /* Copy constexpr from the inherited constructor even if the
+	 inheriting constructor doesn't satisfy the requirements.  */
+      constexpr_p
+	= DECL_DECLARED_CONSTEXPR_P (STRIP_TEMPLATE (inherited_ctor));
+    }
   /* Add the "this" parameter.  */
   this_parm = build_this_parm (fn_type, TYPE_UNQUALIFIED);
   DECL_CHAIN (this_parm) = DECL_ARGUMENTS (fn);
@@ -1600,6 +1728,9 @@  implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
   /* Restore PROCESSING_TEMPLATE_DECL.  */
   processing_template_decl = saved_processing_template_decl;
 
+  if (inherited_ctor && TREE_CODE (inherited_ctor) == TEMPLATE_DECL)
+    fn = add_inherited_template_parms (fn, inherited_ctor);
+
   return fn;
 }
 
@@ -1613,7 +1744,8 @@  defaulted_late_check (tree fn)
   tree ctx = DECL_CONTEXT (fn);
   special_function_kind kind = special_function_p (fn);
   bool fn_const_p = (copy_fn_p (fn) == 2);
-  tree implicit_fn = implicitly_declare_fn (kind, ctx, fn_const_p);
+  tree implicit_fn = implicitly_declare_fn (kind, ctx, fn_const_p,
+					    NULL, NULL);
 
   if (!same_type_p (TREE_TYPE (TREE_TYPE (fn)),
 		    TREE_TYPE (TREE_TYPE (implicit_fn)))
@@ -1766,7 +1898,7 @@  lazily_declare_fn (special_function_kind sfk, tree type)
     }
 
   /* Declare the function.  */
-  fn = implicitly_declare_fn (sfk, type, const_p);
+  fn = implicitly_declare_fn (sfk, type, const_p, NULL, NULL);
 
   /* [class.copy]/8 If the class definition declares a move constructor or
      move assignment operator, the implicitly declared copy constructor is
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index cd328b3..f010560 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -3026,6 +3026,14 @@  push_class_level_binding_1 (tree name, tree x)
       && TREE_TYPE (decl) == error_mark_node)
     decl = TREE_VALUE (decl);
 
+  if (TREE_CODE (decl) == USING_DECL
+      && TREE_CODE (USING_DECL_SCOPE (decl)) == TEMPLATE_TYPE_PARM
+      && DECL_NAME (decl) == TYPE_IDENTIFIER (USING_DECL_SCOPE (decl)))
+    /* This using-declaration declares constructors that inherit from the
+       constructors for the template parameter.  It does not redeclare the
+       name of the template parameter.  */
+    return true;
+
   if (!check_template_shadow (decl))
     return false;
 
@@ -3218,10 +3226,7 @@  do_class_using_decl (tree scope, tree name)
       return NULL_TREE;
     }
   if (MAYBE_CLASS_TYPE_P (scope) && constructor_name_p (name, scope))
-    {
-      error ("%<%T::%D%> names constructor", scope, name);
-      return NULL_TREE;
-    }
+    maybe_warn_cpp0x (CPP0X_INHERITING_CTORS);
   if (constructor_name_p (name, current_class_type))
     {
       error ("%<%T::%D%> names constructor in %qT",
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d81626c..7e8d8b0 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3847,17 +3847,16 @@  arg_from_parm_pack_p (tree arg_pack, tree parm_pack)
   return false;
 }
 
-/* Within the declaration of a template, return all levels of template
-   parameters that apply.  The template parameters are represented as
-   a TREE_VEC, in the form documented in cp-tree.h for template
-   arguments.  */
+/* Given a set of template parameters, return them as a set of template
+   arguments.  The template parameters are represented as a TREE_VEC, in
+   the form documented in cp-tree.h for template arguments.  */
 
 static tree
-current_template_args (void)
+template_parms_to_args (tree parms)
 {
   tree header;
   tree args = NULL_TREE;
-  int length = TMPL_PARMS_DEPTH (current_template_parms);
+  int length = TMPL_PARMS_DEPTH (parms);
   int l = length;
 
   /* If there is only one level of template parameters, we do not
@@ -3866,7 +3865,7 @@  current_template_args (void)
   if (length > 1)
     args = make_tree_vec (length);
 
-  for (header = current_template_parms; header; header = TREE_CHAIN (header))
+  for (header = parms; header; header = TREE_CHAIN (header))
     {
       tree a = copy_node (TREE_VALUE (header));
       int i;
@@ -3903,6 +3902,15 @@  current_template_args (void)
   return args;
 }
 
+/* Within the declaration of a template, return the currently active
+   template parameters as an argument TREE_VEC.  */
+
+static tree
+current_template_args (void)
+{
+  return template_parms_to_args (current_template_parms);
+}
+
 /* Update the declared TYPE by doing any lookups which were thought to be
    dependent, but are not now that we know the SCOPE of the declarator.  */
 
@@ -4904,6 +4912,29 @@  push_template_decl (tree decl)
   return push_template_decl_real (decl, false);
 }
 
+/* FN is an inheriting constructor that inherits from the constructor
+   template INHERITED; turn FN into a constructor template with a matching
+   template header.  */
+
+tree
+add_inherited_template_parms (tree fn, tree inherited)
+{
+  tree inner_parms
+    = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (inherited));
+  inner_parms = copy_node (inner_parms);
+  tree parms
+    = tree_cons (size_int (processing_template_decl + 1),
+		 inner_parms, current_template_parms);
+  tree tmpl = build_template_decl (fn, parms, /*member*/true);
+  tree args = template_parms_to_args (parms);
+  DECL_TEMPLATE_INFO (fn) = build_template_info (tmpl, args);
+  TREE_TYPE (tmpl) = TREE_TYPE (fn);
+  DECL_TEMPLATE_RESULT (tmpl) = fn;
+  DECL_ARTIFICIAL (tmpl) = true;
+  DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
+  return tmpl;
+}
+
 /* Called when a class template TYPE is redeclared with the indicated
    template PARMS, e.g.:
 
@@ -10136,6 +10167,8 @@  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))
+	      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.  */
@@ -10336,9 +10369,14 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
       if (DECL_DEPENDENT_P (t)
 	  || uses_template_parms (USING_DECL_SCOPE (t)))
 	{
-	  r = do_class_using_decl
-	    (tsubst_copy (USING_DECL_SCOPE (t), args, complain, in_decl),
-	     tsubst_copy (DECL_NAME (t), args, complain, in_decl));
+	  tree scope = USING_DECL_SCOPE (t);
+	  tree inst_scope = tsubst_copy (USING_DECL_SCOPE (t), args,
+					 complain, in_decl);
+	  tree name = tsubst_copy (DECL_NAME (t), args, complain, in_decl);
+	  if (TREE_CODE (scope) == TEMPLATE_TYPE_PARM
+	      && name == TYPE_IDENTIFIER (scope))
+	    name = TYPE_IDENTIFIER (inst_scope);
+	  r = do_class_using_decl (inst_scope, name);
 	  if (!r)
 	    r = error_mark_node;
 	  else
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index a41337c..8d555c2 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -3337,6 +3337,8 @@  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))
+    return sfk_inheriting_constructor;
   if (DECL_COPY_CONSTRUCTOR_P (decl))
     return sfk_copy_constructor;
   if (DECL_MOVE_CONSTRUCTOR_P (decl))
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor1.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor1.C
new file mode 100644
index 0000000..9960310
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor1.C
@@ -0,0 +1,17 @@ 
+// { dg-options -std=c++11 }
+
+struct A
+{
+  int i;
+  constexpr A(int i): i(i) {}
+};
+
+struct B: A
+{
+  using A::A;
+};
+
+constexpr B b(42);
+
+#define SA(X) static_assert((X),#X)
+SA(b.i == 42);
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor10.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor10.C
new file mode 100644
index 0000000..de57453
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor10.C
@@ -0,0 +1,14 @@ 
+// { dg-options "-std=c++11" }
+
+struct A
+{
+  template <class... Ts> A(Ts...);
+};
+
+struct B: A
+{
+  using A::A;
+};
+
+B b1(42);
+B b2(1.0, 42, (void*)0);
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C
new file mode 100644
index 0000000..8e8ff01
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C
@@ -0,0 +1,14 @@ 
+// { dg-options "-std=c++11" }
+
+struct A
+{
+  A(int, ...);
+};
+
+struct B: A
+{
+  using A::A;
+};
+
+B b1(42);
+B b2(42, 1.0);			// { dg-error "no match" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor12.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor12.C
new file mode 100644
index 0000000..257487e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor12.C
@@ -0,0 +1,26 @@ 
+// { dg-options "-std=c++11" }
+// { dg-do run }
+
+struct A
+{
+  int i;
+  template <class T>
+  A(T t) noexcept : i(t) {}
+};
+
+struct C
+{
+  C() { throw 42; }
+};
+
+struct B: A, C
+{
+  using A::A;
+};
+
+int main()
+{
+  try { B b(24); }
+  catch (int) { return 0; }
+  __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor13.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor13.C
new file mode 100644
index 0000000..2e18e5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor13.C
@@ -0,0 +1,22 @@ 
+// { dg-options "-std=c++11" }
+
+struct A
+{
+  int i;
+  template <class T> A(T t);
+};
+
+struct C
+{
+  C() = delete;			// { dg-error "declared here" }
+};
+
+struct B: A, C
+{
+  using A::A;			// { dg-error "C::C" }
+};
+
+int main()
+{
+  B b(24);			// { dg-error "B::B" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor2.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor2.C
new file mode 100644
index 0000000..621ba604
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor2.C
@@ -0,0 +1,19 @@ 
+// { dg-options -std=c++11 }
+
+struct A
+{
+  int i;
+  constexpr A(int, int i = num): i(i) {}
+private:
+  static const int num = 42;
+};
+
+struct B: A
+{
+  using A::A;
+};
+
+constexpr B b(24);
+
+#define SA(X) static_assert((X),#X)
+SA(b.i == 42);
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C
new file mode 100644
index 0000000..7116e2f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C
@@ -0,0 +1,17 @@ 
+// { dg-options -std=c++11 }
+
+struct B1 {
+  B1(int);
+};
+struct B2 {
+  B2(int);
+};
+struct D1 : B1, B2 {
+  using B1::B1;			// { dg-error "inherited" }
+  using B2::B2;			// { dg-error "inherited" }
+};			   // ill-formed: attempts to declare D1(int) twice
+struct D2 : B1, B2 {
+  using B1::B1;
+  using B2::B2;
+  D2(int);    // OK: user declaration supersedes both implicit declarations
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor4.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor4.C
new file mode 100644
index 0000000..b6754dc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor4.C
@@ -0,0 +1,18 @@ 
+// From N3337
+// { dg-options -std=c++11 }
+
+struct B1 {
+  B1(int);
+};
+struct B2 {
+  B2(int = 13, int = 42);
+};
+struct D1 : B1 {
+  using B1::B1;
+};
+struct D2 : B2 {
+  using B2::B2;
+};
+
+D1 d1(1);
+D2 d2a(2), d2b(3,4);
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C
new file mode 100644
index 0000000..a8aa6d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C
@@ -0,0 +1,21 @@ 
+// { dg-options "-std=c++11" }
+
+struct B1 {
+  B1(int) { }
+};
+struct B2 {
+  B2(double) { }
+};
+struct D1 : B1 {    // { dg-error "no match" }
+  using B1::B1;	    // implicitly declares D1(int)
+  int x;
+};
+void test() {
+  D1 d(6);	    // OK: d.x is not initialized
+  D1 e;		    // { dg-error "deleted" } D1 has no default constructor
+}
+struct D2 : B2 {
+  using B2::B2;	    // { dg-error "no match" } implicitly declares D2(double)
+  B1 b;
+};
+D2 f(1.0);	    // { dg-error "deleted" } B1 has no default constructor
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor6.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor6.C
new file mode 100644
index 0000000..5ac88d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor6.C
@@ -0,0 +1,15 @@ 
+// { dg-options "-std=c++11" }
+
+extern "C" int printf (const char *, ...);
+template< class T >
+struct D : T {
+  using T::T;
+  // declares all constructors from class T
+  ~D() { printf ("Destroying wrapper\n"); }
+};
+
+struct A {
+  A(int);
+};
+
+D<A> d(42);
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor7.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor7.C
new file mode 100644
index 0000000..2260824
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor7.C
@@ -0,0 +1,18 @@ 
+// { dg-options "-std=c++11" }
+
+struct A
+{
+  int i;
+  template <class T>
+  constexpr A(T t): i(t) {}
+};
+
+struct B: A
+{
+  using A::A;
+};
+
+constexpr B b(42);
+
+#define SA(X) static_assert((X),#X)
+SA(b.i == 42);
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor8.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor8.C
new file mode 100644
index 0000000..d55d3d2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor8.C
@@ -0,0 +1,20 @@ 
+// { dg-options "-std=c++11" }
+
+struct A
+{
+  int i;
+  explicit A(int i): i(i) {}
+};
+
+struct B: A
+{
+  using A::A;
+};
+
+void f(B);
+
+int main()
+{
+  f(B(42));			// OK
+  f(42);			// { dg-error "could not convert" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C
new file mode 100644
index 0000000..dc5e86b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C
@@ -0,0 +1,15 @@ 
+// { dg-options "-std=c++11" }
+
+class A
+{
+  int i;
+protected:
+  A(int i): i(i) {}
+};
+
+struct B: A
+{
+  using A::A;			// { dg-error "protected" }
+};
+
+B b(42);			// { dg-error "this context" }