2016-11-30  Nathan Sidwell  <nathan@acm.org>

	gcc/testsuite/
	* g++.dg/cpp1y/lambda-mangle-1.C: New.

	libiberty/
	* cp-demangle.c (struct p_print_info): Add is_lambda_arg field.
	(d_print_init): Initialize it.
	(d_print_comp_inner) <DEMANGLE_COMPONENT_TEMPLATE_PARAM>: Check
	is_lambda_arg for auto.
	<DEMANGLE_COMPONENT_REFERENCE,
	DEMANGLE_COMPONENT_RVALUE_REFERENCE>: Skip smashing check when
	is_lambda_arg.
	<DEMANGLE_COMPONENT_LAMBDA>: Increment is_lambda_arg around arg
	printing.
	* testsuite/demangle-expected: Add lambda auto mangling cases.

Index: gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.C
===================================================================
--- gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.C	(nonexistent)
+++ gcc/testsuite/g++.dg/cpp1y/lambda-mangle-1.C	(working copy)
@@ -0,0 +1,47 @@
+// { dg-do compile { target c++14 } }
+
+// PR 78252
+
+// We erroneously mangle lambda auto parms asif 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)
+{
+}
+
+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);
+}
+
+// { 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_:" } }
Index: libiberty/cp-demangle.c
===================================================================
--- libiberty/cp-demangle.c	(revision 243016)
+++ libiberty/cp-demangle.c	(working copy)
@@ -343,6 +343,12 @@ struct d_print_info
   struct d_print_mod *modifiers;
   /* Set to 1 if we saw a demangling error.  */
   int demangle_failure;
+  /* Non-zero if we're printing a lambda argument. A template
+     parameter reference actually means 'auto'.  This is a bug in name
+     mangling, and will demangle to something confusing.
+     Unfortunately it can also cause infinite recursion, if we don't
+     interpret this as 'auto'.  */
+  int is_lambda_arg;
   /* The current index into any template argument packs we are using
      for printing, or -1 to print the whole pack.  */
   int pack_index;
@@ -4126,6 +4132,7 @@ d_print_init (struct d_print_info *dpi,
   dpi->opaque = opaque;
 
   dpi->demangle_failure = 0;
+  dpi->is_lambda_arg = 0;
 
   dpi->component_stack = NULL;
 
@@ -4783,33 +4790,35 @@ d_print_comp_inner (struct d_print_info
       }
 
     case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
-      {
-	struct d_print_template *hold_dpt;
-	struct demangle_component *a = d_lookup_template_argument (dpi, dc);
-
-	if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
-	  a = d_index_template_argument (a, dpi->pack_index);
+      if (dpi->is_lambda_arg)
+	d_append_buffer (dpi, "auto", 4);
+      else
+	{
+	  struct d_print_template *hold_dpt;
+	  struct demangle_component *a = d_lookup_template_argument (dpi, dc);
 
-	if (a == NULL)
-	  {
-	    d_print_error (dpi);
-	    return;
-	  }
+	  if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+	    a = d_index_template_argument (a, dpi->pack_index);
 
-	/* While processing this parameter, we need to pop the list of
-	   templates.  This is because the template parameter may
-	   itself be a reference to a parameter of an outer
-	   template.  */
+	  if (a == NULL)
+	    {
+	      d_print_error (dpi);
+	      return;
+	    }
 
-	hold_dpt = dpi->templates;
-	dpi->templates = hold_dpt->next;
+	  /* While processing this parameter, we need to pop the list
+	     of templates.  This is because the template parameter may
+	     itself be a reference to a parameter of an outer
+	     template.  */
 
-	d_print_comp (dpi, options, a);
+	  hold_dpt = dpi->templates;
+	  dpi->templates = hold_dpt->next;
 
-	dpi->templates = hold_dpt;
+	  d_print_comp (dpi, options, a);
 
-	return;
-      }
+	  dpi->templates = hold_dpt;
+	}
+      return;
 
     case DEMANGLE_COMPONENT_CTOR:
       d_print_comp (dpi, options, dc->u.s_ctor.name);
@@ -4946,7 +4955,8 @@ d_print_comp_inner (struct d_print_info
       {
 	/* Handle reference smashing: & + && = &.  */
 	const struct demangle_component *sub = d_left (dc);
-	if (sub->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM)
+	if (!dpi->is_lambda_arg
+	    && sub->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM)
 	  {
 	    struct d_saved_scope *scope = d_get_saved_scope (dpi, sub);
 	    struct demangle_component *a;
@@ -5616,7 +5626,14 @@ d_print_comp_inner (struct d_print_info
 
     case DEMANGLE_COMPONENT_LAMBDA:
       d_append_string (dpi, "{lambda(");
+      /* We need to notice if we're printing a lambda argument type.
+	 When this is true, any template parameter reference is
+	 actually an instance of 'auto'.  Fortunately we can't meet
+	 real uses of template parameters inside the lambda
+	 arguments.  */
+      dpi->is_lambda_arg++;
       d_print_comp (dpi, options, dc->u.s_unary_num.sub);
+      dpi->is_lambda_arg--;
       d_append_string (dpi, ")#");
       d_append_num (dpi, dc->u.s_unary_num.num + 1);
       d_append_char (dpi, '}');
Index: libiberty/testsuite/demangle-expected
===================================================================
--- libiberty/testsuite/demangle-expected	(revision 243016)
+++ libiberty/testsuite/demangle-expected	(working copy)
@@ -4634,3 +4634,27 @@ _Z12binary_rightIJLi1ELi2ELi3EEEv1AIXfRp
 # ?: expression with missing third component could crash.
 AquT_quT_4mxautouT_4mxxx
 AquT_quT_4mxautouT_4mxxx
+
+# pr c++/78252 unfortunate bug in g++'s lambda mangling would lead to
+# incorrect demangles, and at worst unbounded recursion
+_Z7forwardIRZ3FoovEUlRT_E_EOS0_S1_
+Foo()::{lambda(auto&)#1}& forward<Foo()::{lambda(auto&)#1}&>(Foo()::{lambda(auto&)#1}&)
+
+_Z7forwardIZ3FoovEUlRiRT_E_EOS1_S2_
+Foo()::{lambda(int&, auto&)#1}&& forward<Foo()::{lambda(int&, auto&)#1}>(Foo()::{lambda(int&, auto&)#1}&)
+
+_Z7forwardIZ3FoovEUlRT_R1XIiEE0_EOS0_S1_
+Foo()::{lambda(auto&, X<int>&)#2}&& forward<Foo()::{lambda(auto&, X<int>&)#2}>(Foo()::{lambda(auto&, X<int>&)#2}&)
+
+_Z7forwardIZ3FoovEUlPA5_T_E1_EOS0_RS0_
+Foo()::{lambda(auto (*&&forward<Foo()::{lambda(auto (*) [5])#3}>(auto&)) [5])#3}
+
+_Z3eatIZ3FoovEUlRiRT_E_EvS2_
+void eat<Foo()::{lambda(int&, auto&)#1}>(Foo()::{lambda(int&, auto&)#1}&)
+
+_Z3eatIZ3FoovEUlRT_R1XIiEE0_EvS1_
+void eat<Foo()::{lambda(auto&, X<int>&)#2}>(Foo()::{lambda(auto&, X<int>&)#2}&)
+
+_Z3eatIZ3FoovEUlPA5_T_E1_EvRS0_
+void eat<Foo()::{lambda(auto (*) [5])#3}>(Foo()::{lambda(auto (*&) [5])#3})
+
