diff mbox series

[demangler] : Revert and update generic lambda demangling

Message ID 85e8e7fc-1676-dd47-e8b3-2da467d9a825@acm.org
State New
Headers show
Series [demangler] : Revert and update generic lambda demangling | expand

Commit Message

Nathan Sidwell Sept. 21, 2017, 3:51 p.m. UTC
My recent change to generic lambda demangling was incorrect.  It wrapped 
the function type inside the local name, which allowed the printer to 
see the correct set of template parameters (and not recurse).  Except 
there was a hack to not do that at the outer most level.  but that still 
ends up failing in some cases.

This patch takes a different approach. I revert the previous change to 
teach d_local_name to parse a function type.  Instead I teach 
d_print_comp_inner that it needs to pull template-parms from inside a 
LOCAL_NAME.

This further exposes an existing display problem, namely that the return 
type of a template function instantiation containing a local name is 
shown at the start of the demangle -- which is terribly confusing:

'float Foo<int>()::X::fn()'

That 'float' looks like it is the return type of X::fn, but it is not. 
However, this is an existing problem, and changing the behaviour will 
change other demangles.  I shall post a separate patch for that.

nathan
diff mbox series

Patch

2017-09-21  Nathan Sidwell  <nathan@acm.org>

	PR demangler/82195
	* cp-demangle.c (d_name): Revert addition of 'toplevel' parm.
	(has_return_type): Recurse for DEMANGLE_COMPONENT_LOCAL_NAME.
	(d_encoding): Revert d_name change.  Use is_fnqual_component_type
	to strip modifiers that do not belong.
	(d_special_name, d_class_enum_type): Revert d_name call change.
	(d_expresion_1): Commonize DEMANGLE_COMPONENT_UNARY building.
	(d_local_name): Revert parsing of a function type.
	(d_print_comp_inner): An inner LOCAL_NAME might contain a
	TEMPLATE.
	* testsuite/demangle-expected: Add & adjust tests

Index: cp-demangle.c
===================================================================
--- cp-demangle.c	(revision 253070)
+++ cp-demangle.c	(working copy)
@@ -425,7 +425,7 @@  is_ctor_dtor_or_conversion (struct deman
 
 static struct demangle_component *d_encoding (struct d_info *, int);
 
-static struct demangle_component *d_name (struct d_info *, int);
+static struct demangle_component *d_name (struct d_info *);
 
 static struct demangle_component *d_nested_name (struct d_info *);
 
@@ -484,7 +484,7 @@  static struct demangle_component *d_expr
 
 static struct demangle_component *d_expr_primary (struct d_info *);
 
-static struct demangle_component *d_local_name (struct d_info *, int);
+static struct demangle_component *d_local_name (struct d_info *);
 
 static int d_discriminator (struct d_info *);
 
@@ -1259,6 +1259,8 @@  has_return_type (struct demangle_compone
     {
     default:
       return 0;
+    case DEMANGLE_COMPONENT_LOCAL_NAME:
+      return has_return_type (d_right (dc));
     case DEMANGLE_COMPONENT_TEMPLATE:
       return ! is_ctor_dtor_or_conversion (d_left (dc));
     FNQUAL_COMPONENT_CASE:
@@ -1301,25 +1303,22 @@  static struct demangle_component *
 d_encoding (struct d_info *di, int top_level)
 {
   char peek = d_peek_char (di);
+  struct demangle_component *dc;
 
   if (peek == 'G' || peek == 'T')
-    return d_special_name (di);
+    dc = d_special_name (di);
   else
     {
-      struct demangle_component *dc, *dcr;
-
-      dc = d_name (di, top_level);
+      dc = d_name (di);
 
-      if (dc != NULL && top_level && (di->options & DMGL_PARAMS) == 0)
+      if (!dc)
+	/* Failed already.  */;
+      else if (top_level && (di->options & DMGL_PARAMS) == 0)
 	{
 	  /* Strip off any initial CV-qualifiers, as they really apply
 	     to the `this' parameter, and they were not output by the
 	     v2 demangler without DMGL_PARAMS.  */
-	  while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
-		 || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
-		 || dc->type == DEMANGLE_COMPONENT_CONST_THIS
-		 || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
-		 || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
+	  while (is_fnqual_component_type (dc->type))
 	    dc = d_left (dc);
 
 	  /* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then
@@ -1327,22 +1326,27 @@  d_encoding (struct d_info *di, int top_l
 	     really apply here; this happens when parsing a class
 	     which is local to a function.  */
 	  if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME)
+	    while (is_fnqual_component_type (d_right (dc)->type))
+	      d_right (dc) = d_left (d_right (dc));
+	}
+      else
+	{
+	  peek = d_peek_char (di);
+	  if (peek != '\0' && peek != 'E')
 	    {
-	      dcr = d_right (dc);
-	      while (is_fnqual_component_type (dcr->type))
-		dcr = d_left (dcr);
-	      dc->u.s_binary.right = dcr;
-	    }
+	      struct demangle_component *ftype;
 
-	  return dc;
+	      ftype = d_bare_function_type (di, has_return_type (dc));
+	      if (ftype)
+		dc = d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME,
+				  dc, ftype);
+	      else
+		dc = NULL;
+	    }
 	}
-
-      peek = d_peek_char (di);
-      if (dc == NULL || peek == '\0' || peek == 'E')
-	return dc;
-      dcr = d_bare_function_type (di, has_return_type (dc));
-      return d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, dc, dcr);
     }
+
+  return dc;
 }
 
 /* <tagged-name> ::= <name> B <source-name> */
@@ -1383,7 +1387,7 @@  d_abi_tags (struct d_info *di, struct de
 */
 
 static struct demangle_component *
-d_name (struct d_info *di, int top_level)
+d_name (struct d_info *di)
 {
   char peek = d_peek_char (di);
   struct demangle_component *dc;
@@ -1394,7 +1398,7 @@  d_name (struct d_info *di, int top_level
       return d_nested_name (di);
 
     case 'Z':
-      return d_local_name (di, top_level);
+      return d_local_name (di);
 
     case 'U':
       return d_unqualified_name (di);
@@ -2079,11 +2083,11 @@  d_special_name (struct d_info *di)
 
 	case 'H':
 	  return d_make_comp (di, DEMANGLE_COMPONENT_TLS_INIT,
-			      d_name (di, 0), NULL);
+			      d_name (di), NULL);
 
 	case 'W':
 	  return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER,
-			      d_name (di, 0), NULL);
+			      d_name (di), NULL);
 
 	default:
 	  return NULL;
@@ -2095,11 +2099,11 @@  d_special_name (struct d_info *di)
 	{
 	case 'V':
 	  return d_make_comp (di, DEMANGLE_COMPONENT_GUARD,
-			      d_name (di, 0), NULL);
+			      d_name (di), NULL);
 
 	case 'R':
 	  {
-	    struct demangle_component *name = d_name (di, 0);
+	    struct demangle_component *name = d_name (di);
 	    return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, name,
 				d_number_component (di));
 	  }
@@ -2935,7 +2939,7 @@  d_bare_function_type (struct d_info *di,
 static struct demangle_component *
 d_class_enum_type (struct d_info *di)
 {
-  return d_name (di, 0);
+  return d_name (di);
 }
 
 /* <array-type> ::= A <(positive dimension) number> _ <(element) type>
@@ -3380,13 +3384,10 @@  d_expression_1 (struct d_info *di)
 
 	    if (suffix)
 	      /* Indicate the suffix variant for d_print_comp.  */
-	      return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
-				  d_make_comp (di,
-					       DEMANGLE_COMPONENT_BINARY_ARGS,
-					       operand, operand));
-	    else
-	      return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
-				  operand);
+	      operand = d_make_comp (di, DEMANGLE_COMPONENT_BINARY_ARGS,
+				     operand, operand);
+
+	    return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, operand);
 	  }
 	case 2:
 	  {
@@ -3568,7 +3569,7 @@  d_expr_primary (struct d_info *di)
 */
 
 static struct demangle_component *
-d_local_name (struct d_info *di, int top_level)
+d_local_name (struct d_info *di)
 {
   struct demangle_component *function;
   struct demangle_component *name;
@@ -3577,6 +3578,8 @@  d_local_name (struct d_info *di, int top
     return NULL;
 
   function = d_encoding (di, 0);
+  if (!function)
+    return NULL;
 
   if (! d_check_char (di, 'E'))
     return NULL;
@@ -3601,7 +3604,7 @@  d_local_name (struct d_info *di, int top
 	    return NULL;
 	}
 
-      name = d_name (di, 0);
+      name = d_name (di);
 
       if (name
 	  /* Lambdas and unnamed types have internal discriminators
@@ -3609,18 +3612,6 @@  d_local_name (struct d_info *di, int top
 	  && name->type != DEMANGLE_COMPONENT_LAMBDA
 	  && name->type != DEMANGLE_COMPONENT_UNNAMED_TYPE)
 	{
-	  if (!top_level
-	      && d_peek_char (di) != 0 /* Not end of string.  */
-	      && d_peek_char (di) != 'E' /* Not end of nested encoding.  */
-	      && d_peek_char (di) != '_') /* Not discriminator.  */
-	    {
-	      struct demangle_component *args;
-
-	      args = d_bare_function_type (di, has_return_type (name));
-	      name = d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME,
-				  name, args);
-	    }
-
 	  /* Read and ignore an optional discriminator.  */
 	  if (! d_discriminator (di))
 	    return NULL;
@@ -4710,32 +4701,21 @@  d_print_comp_inner (struct d_print_info
 	    return;
 	  }
 
-	/* If typed_name is a template, then it applies to the
-	   function type as well.  */
-	if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
-	  {
-	    dpt.next = dpi->templates;
-	    dpi->templates = &dpt;
-	    dpt.template_decl = typed_name;
-	  }
-
 	/* If typed_name is a DEMANGLE_COMPONENT_LOCAL_NAME, then
 	   there may be CV-qualifiers on its right argument which
-	   really apply here; this happens when parsing a class which
+	   really apply here; this happens when parsing a class that
 	   is local to a function.  */
 	if (typed_name->type == DEMANGLE_COMPONENT_LOCAL_NAME)
 	  {
-	    struct demangle_component *local_name;
-
-	    local_name = d_right (typed_name);
-	    if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
-	      local_name = local_name->u.s_unary_num.sub;
-	    if (local_name == NULL)
+	    typed_name = d_right (typed_name);
+	    if (typed_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
+	      typed_name = typed_name->u.s_unary_num.sub;
+	    if (typed_name == NULL)
 	      {
 		d_print_error (dpi);
 		return;
 	      }
-	    while (is_fnqual_component_type (local_name->type))
+	    while (is_fnqual_component_type (typed_name->type))
 	      {
 		if (i >= sizeof adpm / sizeof adpm[0])
 		  {
@@ -4747,15 +4727,24 @@  d_print_comp_inner (struct d_print_info
 		adpm[i].next = &adpm[i - 1];
 		dpi->modifiers = &adpm[i];
 
-		adpm[i - 1].mod = local_name;
+		adpm[i - 1].mod = typed_name;
 		adpm[i - 1].printed = 0;
 		adpm[i - 1].templates = dpi->templates;
 		++i;
 
-		local_name = d_left (local_name);
+		typed_name = d_left (typed_name);
 	      }
 	  }
 
+	/* If typed_name is a template, then it applies to the
+	   function type as well.  */
+	if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
+	  {
+	    dpt.next = dpi->templates;
+	    dpi->templates = &dpt;
+	    dpt.template_decl = typed_name;
+	  }
+
 	d_print_comp (dpi, options, d_right (dc));
 
 	if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
Index: testsuite/demangle-expected
===================================================================
--- testsuite/demangle-expected	(revision 253070)
+++ testsuite/demangle-expected	(working copy)
@@ -4739,14 +4739,19 @@  __thunk_4294967297__$_1x
 # demangler/82195 members of lambdas
 --no-params
 _ZZZ3FoovENKUlT_E_clIiEEfS_EN5Local2fnEv
-Foo()::float {lambda(auto:1)#1}::operator()<int>(int) const::Local::fn()
-Foo()::float {lambda(auto:1)#1}::operator()<int>(int) const::Local::fn
+float Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::Local::fn()
+float Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::Local::fn
 --no-params
 _Z7CaptureIZZ3FoovENKUlT_E_clIiEEvS0_EUlvE_EvOS0_
-void Capture<Foo()::void {lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>(Foo()::void {lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}&&)
-Capture<Foo()::void {lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>
+void Capture<void Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>(void Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}&&)
+Capture<void Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>
 --no-params
 _Z4FrobIZZ3FoovENKUlT_E_clIiEEvS0_EUlvE_Evv
-void Frob<Foo()::void {lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>()
-Frob<Foo()::void {lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>
+void Frob<void Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>()
+Frob<void Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>
 #
+# A lambda {local-class::member-fn}
+--no-params
+_ZZ3FoovENKUlT_E_clIiEEfS_
+float Foo()::{lambda(auto:1)#1}::operator()<int>(int) const
+Foo()::{lambda(auto:1)#1}::operator()<int>