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

	gcc/
	PR c++/78621
	* doc/invoke.texi (-fabi-version): Document generic lambda
	mangling for version 11.

	gcc/cp/
	PR c++/78621
	* cp-tree.h (make_auto_for_mangle): Declare.
	* mangle.c (write_closure_type_name): Handle generic lambdas
	correctly.
	* pt.c (tsubst): Add {TYPE,EXPR}_PACK_EXPANSION handling.
	(make_auto_raw): Break out of ...
	(make_auto_1): ... here.  Call it.
	(make_auto_for_mangle): New.

	gcc/testsuite/
	PR c++/78621
	* g++.dg/cpp1y/lambda-mangle-1.C: New.
	* g++.dg/cpp1y/lambda-mangle-2.C: New.
	* g++.dg/cpp1y/lambda-mangle-3.C: New.

	libiberty/
	PR c++/78621
	* testsuite/demangle-expected: Add fixed-ABI generic lambda tests.

Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 243371)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -6108,6 +6108,7 @@
 extern void check_template_variable		(tree);
 extern tree make_auto				(void);
 extern tree make_decltype_auto			(void);
+extern tree make_auto_for_mangle		(tree, tree);
 extern tree make_template_placeholder		(tree);
 extern tree do_auto_deduction                   (tree, tree, tree);
 extern tree do_auto_deduction                   (tree, tree, tree,
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c	(revision 243371)
+++ gcc/cp/mangle.c	(working copy)
@@ -1640,6 +1640,19 @@
   tree lambda = CLASSTYPE_LAMBDA_EXPR (type);
   tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
 
+  if (generic_lambda_fn_p (fn))
+    {
+      /* A generic lambda's auto parms are represented as distinct
+         TEMPLATE_TYPE_PARMs, which are both distinct and not is_auto.
+         But we must mangle (& squangle) them as (the same) 'auto'.
+         So do some substitution to arrange that.  */
+      if (abi_warn_or_compat_version_crosses (11))
+	G.need_abi_warning = 1;
+
+      if (abi_version_at_least (11))
+	parms = make_auto_for_mangle (fn, parms);
+    }
+
   MANGLE_TRACE_TREE ("closure-type-name", type);
 
   write_string ("Ul");
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 243371)
+++ gcc/cp/pt.c	(working copy)
@@ -13813,6 +13813,42 @@
 	return r;
       }
 
+    case TYPE_PACK_EXPANSION:
+    case EXPR_PACK_EXPANSION:
+      {
+	tree r;
+
+	if (code == EXPR_PACK_EXPANSION)
+	  {
+	    r = make_node (code);
+	    TREE_TYPE (r) = type;
+	    TREE_CONSTANT (r) = TREE_CONSTANT (t);
+	    PACK_EXPANSION_SIZEOF_P (r) = PACK_EXPANSION_SIZEOF_P (t);
+	  }
+	else
+	  {
+	    r = cxx_make_type (code);
+	    SET_TYPE_STRUCTURAL_EQUALITY (r);
+	  }
+
+	WILDCARD_PACK_P (r) = WILDCARD_PACK_P (t);
+	PACK_EXPANSION_LOCAL_P (r) = PACK_EXPANSION_LOCAL_P (t);
+
+	tree pattern = PACK_EXPANSION_PATTERN (t);
+	pattern = tsubst (pattern, args, complain, in_decl);
+	SET_PACK_EXPANSION_PATTERN (r, pattern);
+
+	tree packs = PACK_EXPANSION_PARAMETER_PACKS (t);
+	packs = tsubst (packs, args, complain, in_decl);
+	PACK_EXPANSION_PARAMETER_PACKS (r) = packs;
+
+	tree extra = PACK_EXPANSION_EXTRA_ARGS (t);
+	extra = tsubst (extra, args, complain, in_decl);
+	PACK_EXPANSION_EXTRA_ARGS (r) = extra;
+
+	return r;
+      }
+
     case VOID_CST:
     case INTEGER_CST:
     case REAL_CST:
@@ -24278,20 +24314,19 @@
     }
 }
 
-/* Returns a type which represents 'auto' or 'decltype(auto)'.  We use a
-   TEMPLATE_TYPE_PARM with a level one deeper than the actual template
-   parms.  If set_canonical is true, we set TYPE_CANONICAL on it.  */
+/* Returns a template type parm to represent 'auto' or
+   'decltype(auto)'.  If SET_CANONICAL is true, we set TYPE_CANONICAL
+   on it.  set the parm's LEVEL and ORIG_LEVEL as specified.  */
 
 static tree
-make_auto_1 (tree name, bool set_canonical)
+make_auto_raw (tree name, bool set_canonical, int level, int orig_level)
 {
   tree au = cxx_make_type (TEMPLATE_TYPE_PARM);
   TYPE_NAME (au) = build_decl (input_location,
 			       TYPE_DECL, name, au);
   TYPE_STUB_DECL (au) = TYPE_NAME (au);
   TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
-    (0, processing_template_decl + 1, processing_template_decl + 1,
-     TYPE_NAME (au), NULL_TREE);
+    (0, level, orig_level, TYPE_NAME (au), NULL_TREE);
   if (set_canonical)
     TYPE_CANONICAL (au) = canonical_type_parameter (au);
   DECL_ARTIFICIAL (TYPE_NAME (au)) = 1;
@@ -24300,6 +24335,18 @@
   return au;
 }
 
+/* Returns a type to represent 'auto' or 'decltype(auto)'.  We use a
+   TEMPLATE_TYPE_PARM with a level one deeper than the actual template
+   parms.  If set_canonical is true, we set TYPE_CANONICAL on it.  */
+
+static tree
+make_auto_1 (tree name, bool set_canonical)
+{
+  return make_auto_raw (name, set_canonical,
+			processing_template_decl + 1,
+			processing_template_decl + 1);
+}
+
 tree
 make_decltype_auto (void)
 {
@@ -24352,6 +24399,25 @@
   return decl;
 }
 
+/* FN a generic lambda function and PARMS is its parameters.  Perform
+   appropriate substitution turning the distinct template type parms
+   into a regular auto template type parm suitable for mangler
+   use.  */
+
+tree
+make_auto_for_mangle (tree fn, tree parms)
+{
+  tree ti_args = TI_ARGS (DECL_TEMPLATE_INFO (fn));
+  unsigned ix = NUM_TMPL_ARGS (INNERMOST_TEMPLATE_ARGS (ti_args));
+  tree args = make_tree_vec (ix);
+  tree auto_parm = make_auto_raw (auto_identifier, true,
+				  1, TMPL_ARGS_DEPTH (ti_args));
+  while (ix--)
+    TREE_VEC_ELT (args, ix) = auto_parm;
+
+  return tsubst (parms, args, tf_none, NULL_TREE);
+}
+
 /* Given type ARG, return std::initializer_list<ARG>.  */
 
 static tree
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 243371)
+++ gcc/doc/invoke.texi	(working copy)
@@ -2250,7 +2250,7 @@
 attributes (e.g. @samp{stdcall}).
 
 Version 11, which first appeared in G++ 7, corrects the mangling of
-sizeof... expressions.  It also implies
+sizeof... expressions and generic lambdas.  It also implies
 @option{-fnew-inheriting-ctors}.
 
 See also @option{-Wabi}.
Index: gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.C
===================================================================
--- gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.C	(working copy)
@@ -0,0 +1,81 @@
+// { dg-do compile { target c++14 } }
+// { dg-additional-options "-fabi-version=10" }
+
+// PRs 78252, 78621
+
+// We erroneously mangle lambda auto parms as-if template parameters (T<n>_),
+// rather than auto (Da).  While that's unfortunate, it'd be best if
+// we didn't accidentally change that.
+
+template<typename T> class X;
+
+template<typename T>
+T &&forward (T &v)
+{
+  return static_cast<T &&> (v);
+}
+
+template<typename T>
+void eat (T &v)
+{
+}
+
+template<typename S, typename T>
+  void eat (S &, T &v)
+{
+}
+
+void Foo ()
+{
+  auto lam = [](auto &) { };
+  auto lam_1 = [](int &, auto &) { };
+  auto lam_2 = [](auto &, X<int> &) { };
+  auto lam_3 = [](auto (*)[5]) { };
+
+  forward (lam);
+  forward (lam_1);
+  forward (lam_2);
+  forward (lam_3);
+
+  eat (lam);
+  eat (lam_1);
+  eat (lam_2);
+  eat (lam_3);
+
+  auto lambda_1 = [](float *, float *) { };
+  auto lambda_2 = [](auto *, auto *) { };
+
+  int *i;
+  
+  eat (i, lambda_1);
+  eat (i, lambda_2);
+}
+
+template<typename X> void Bar ()
+{
+  auto lambda_1 = [](X *, float *, float *) { };
+  auto lambda_2 = [](X *, auto *, auto *) { };
+
+  int *i;
+  
+  eat (i, lambda_1);
+  eat (i, lambda_2);
+}
+
+void Baz ()
+{
+  Bar<short> ();
+}
+
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_E_EOS0_S1_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRiRT_E0_EOS1_S2_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRT_R1XIiEE1_EOS0_S1_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlPA5_T_E2_EOS0_RS0_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRT_E_EvS1_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRiRT_E0_EvS2_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRT_R1XIiEE1_EvS1_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPA5_T_E2_EvRS0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPfS1_E3_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPT_PT0_E4_EvRS1_RS3_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPfS3_E_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPT_PT0_E0_EvRS3_RS5_:" } }
Index: gcc/testsuite/g++.dg/cpp1y/lambda-mangle-2.C
===================================================================
--- gcc/testsuite/g++.dg/cpp1y/lambda-mangle-2.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp1y/lambda-mangle-2.C	(working copy)
@@ -0,0 +1,88 @@
+// { dg-do compile { target c++14 } }
+
+// PRs 78621
+
+// We erroneously mangled lambda auto parms as-if template parameters (T<n>_),
+// rather than auto (Da). Fixed in abi version 11
+
+template<typename T> class X;
+
+template<typename T>
+T &&forward (T &v)
+{
+  return static_cast<T &&> (v);
+}
+
+template<typename T>
+void eat (T &v)
+{
+}
+
+template<typename S, typename T>
+  void eat (S &, T &v)
+{
+}
+
+void Foo ()
+{
+  auto lam = [](auto &) { };
+  auto lam_1 = [](int &, auto &) { };
+  auto lam_2 = [](auto &, X<int> &) { };
+  auto lam_3 = [](auto (*)[5]) { };
+
+  forward (lam);
+  forward (lam_1);
+  forward (lam_2);
+  forward (lam_3);
+
+  eat (lam);
+  eat (lam_1);
+  eat (lam_2);
+  eat (lam_3);
+
+  // The auto lambda should mangle similarly to the non-auto one
+  auto lambda_1 = [](float *, float *) { };
+  auto lambda_2 = [](auto *, auto *) { };
+  auto lambda_3 = [](auto *, auto *) { };
+
+  int *i;
+  
+  eat (i, lambda_1);
+  eat (i, lambda_2);
+
+  // The autos should squangle to the first one.
+  eat (lambda_2, lambda_3);
+}
+
+template<typename X> void Bar ()
+{
+  auto lambda_1 = [](X *, float *, float *) { };
+  auto lambda_2 = [](X *, auto *, auto *) { };
+  auto lambda_3 = [](X *, auto *...) {};
+  
+  int *i;
+  
+  eat (i, lambda_1);
+  eat (i, lambda_2);
+  eat (i, lambda_3);
+}
+
+void Baz ()
+{
+  Bar<short> ();
+}
+
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRDaE_EOT_RS2_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRiRDaE0_EOT_RS3_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlRDaR1XIiEE1_EOT_RS5_:" } }
+// { dg-final { scan-assembler "_Z7forwardIZ3FoovEUlPA5_DaE2_EOT_RS3_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRDaE_EvRT_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRiRDaE0_EvRT_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlRDaR1XIiEE1_EvRT_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPA5_DaE2_EvRT_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPfS1_E3_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3FoovEUlPDaS1_E4_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIZ3FoovEUlPDaS0_E4_Z3FoovEUlS0_S0_E5_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPfS3_E_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPDaS3_E0_EvRT_RT0_:" } }
+// { dg-final { scan-assembler "_Z3eatIPiZ3BarIsEvvEUlPsPDazE1_EvRT_RT0_:" } }
Index: gcc/testsuite/g++.dg/cpp1y/lambda-mangle-3.C
===================================================================
--- gcc/testsuite/g++.dg/cpp1y/lambda-mangle-3.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp1y/lambda-mangle-3.C	(working copy)
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++14 } }
+// { dg-additional-options "-Wabi=10" }
+
+// PRs 78621
+
+// check we warn about changed mangling of generic lambdas.
+
+template<typename T>
+void eat (T &v) // { dg-warning "mangled name" }
+{
+}
+
+void Foo ()
+{
+  auto lam = [](auto &) { };
+
+  eat (lam);
+}
Index: libiberty/testsuite/demangle-expected
===================================================================
--- libiberty/testsuite/demangle-expected	(revision 243371)
+++ libiberty/testsuite/demangle-expected	(working copy)
@@ -4634,3 +4634,11 @@
 # ?: expression with missing third component could crash.
 AquT_quT_4mxautouT_4mxxx
 AquT_quT_4mxautouT_4mxxx
+
+# pr78621 We were incorrectly mangling generic lambdas.  Check the fix
+# for that demangles as expected
+_Z3eatIPiZ3FoovEUlPDaS1_E4_EvRT_RT0_
+void eat<int*, Foo()::{lambda(auto*, auto*)#6}>(int*&, Foo()::{lambda(auto*, auto*)#6}&)
+
+_Z3eatIPiZ3BarIsEvvEUlPsPDaS3_E0_EvRT_RT0_
+void eat<int*, void Bar<short>()::{lambda(short*, auto*, auto*)#2}>(int*&, void Bar<short>()::{lambda(short*, auto*, auto*)#2}&)
