public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [demangler] Fix nested generic lambda
@ 2017-09-15 12:04 Nathan Sidwell
  2017-09-15 16:15 ` Pedro Alves
  0 siblings, 1 reply; 3+ messages in thread
From: Nathan Sidwell @ 2017-09-15 12:04 UTC (permalink / raw)
  To: GCC Patches; +Cc: palves

[-- Attachment #1: Type: text/plain, Size: 2107 bytes --]

This patch fixes PR82195, which turned out to be a demangler bug -- the 
specification and the compiler were DTRT.

The originating source contained a non-generic lambda within a generic 
lambda.  Because we had an older GDB without recursion protection in its 
demangler, GDB died, and that kind of makes debugging difficult.

I did reduce the testcase further to:

void Foo () {
   // Foo()::<lambda(auto:1)> [with auto:1 = int]
   // _ZZ3FoovENKUlT_E_clIiEEfS_
   [](auto) ->float {
     struct Local {
       // void Foo()::<lambda(auto:1)>::Local::fn() [with auto:1 = int]
       // _ZZZ3FoovENKUlT_E_clIiEEfS_EN5Local2fnEv
       static void fn () {}
     };
     Local::fn ();
     return 0.0f;
   } (0);
}

The salient point is that we have to mangle names within the local 
context of an instantiation of a lambda's templated operator ().  The 
demangler was not expecting a local name:
    Z <context> E <local-entity> [discriminator]
to have a function as a local-entity.  This wasn't noticed because it 
still managed to parse the trailing parameter types in the context of 
d_local_name's caller, as there usually is no discriminator.  But those 
parameters got attached to the wrong level of the demangle tree.

When those parameters contain template parameters that refer to the 
instantiation parameters of the local entity, it all goes wrong.  (The 
instantiation parameters get correctly attached to the local-entity).

After parsing a local entity name we peek at the next character, and if 
it's not NUL, 'E' (end of containing scope) or '_' (discriminator) we 
parse function parameters before closing out the local name.

A complication is that we need to know if we're the outermost local 
name, and not do it in that case.  Otherwise we end up gluing the 
parameters too deeply and consequently --no-param demangles break 
(you'll see there's similar funky code in d_encoding).  Luckily in such 
cases we cannot meet the templated case.

Applying to trunk.

Pedro, would you like me to port to gdb's libiberty, or will you do a 
merge in the near future?

nathan

-- 
Nathan Sidwell

[-- Attachment #2: pr82195.diff --]
[-- Type: text/x-patch, Size: 5516 bytes --]

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

	PR demangle/82195
	* cp-demangle.c (d_name): Add 'toplevel' parm.  Pass to	...
	(d_local_name): ... here.  Parse trailing function args on nested
	local_name.
	(d_encoding, d_special_name, d_class_enum_type): Adjust d_name calls.
	* testsuite/demangle-expected: Add tests.

Index: cp-demangle.c
===================================================================
--- cp-demangle.c	(revision 252802)
+++ 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 *);
+static struct demangle_component *d_name (struct d_info *, int);
 
 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 *);
+static struct demangle_component *d_local_name (struct d_info *, int);
 
 static int d_discriminator (struct d_info *);
 
@@ -1308,7 +1308,7 @@ d_encoding (struct d_info *di, int top_l
     {
       struct demangle_component *dc, *dcr;
 
-      dc = d_name (di);
+      dc = d_name (di, top_level);
 
       if (dc != NULL && top_level && (di->options & DMGL_PARAMS) == 0)
 	{
@@ -1383,7 +1383,7 @@ d_abi_tags (struct d_info *di, struct de
 */
 
 static struct demangle_component *
-d_name (struct d_info *di)
+d_name (struct d_info *di, int top_level)
 {
   char peek = d_peek_char (di);
   struct demangle_component *dc;
@@ -1394,7 +1394,7 @@ d_name (struct d_info *di)
       return d_nested_name (di);
 
     case 'Z':
-      return d_local_name (di);
+      return d_local_name (di, top_level);
 
     case 'U':
       return d_unqualified_name (di);
@@ -2079,11 +2079,11 @@ d_special_name (struct d_info *di)
 
 	case 'H':
 	  return d_make_comp (di, DEMANGLE_COMPONENT_TLS_INIT,
-			      d_name (di), NULL);
+			      d_name (di, 0), NULL);
 
 	case 'W':
 	  return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER,
-			      d_name (di), NULL);
+			      d_name (di, 0), NULL);
 
 	default:
 	  return NULL;
@@ -2094,11 +2094,12 @@ d_special_name (struct d_info *di)
       switch (d_next_char (di))
 	{
 	case 'V':
-	  return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL);
+	  return d_make_comp (di, DEMANGLE_COMPONENT_GUARD,
+			      d_name (di, 0), NULL);
 
 	case 'R':
 	  {
-	    struct demangle_component *name = d_name (di);
+	    struct demangle_component *name = d_name (di, 0);
 	    return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, name,
 				d_number_component (di));
 	  }
@@ -2934,7 +2935,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);
+  return d_name (di, 0);
 }
 
 /* <array-type> ::= A <(positive dimension) number> _ <(element) type>
@@ -3567,7 +3568,7 @@ d_expr_primary (struct d_info *di)
 */
 
 static struct demangle_component *
-d_local_name (struct d_info *di)
+d_local_name (struct d_info *di, int top_level)
 {
   struct demangle_component *function;
   struct demangle_component *name;
@@ -3600,14 +3601,30 @@ d_local_name (struct d_info *di)
 	    return NULL;
 	}
 
-      name = d_name (di);
+      name = d_name (di, 0);
+
       if (name
-	  /* Lambdas and unnamed types have internal discriminators.  */
+	  /* Lambdas and unnamed types have internal discriminators
+	     and are not functions.  */
 	  && name->type != DEMANGLE_COMPONENT_LAMBDA
-	  && name->type != DEMANGLE_COMPONENT_UNNAMED_TYPE
-	  /* Otherwise read and ignore an optional discriminator.  */
-	  && ! d_discriminator (di))
-	return NULL;
+	  && 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;
+	}
 
       if (num >= 0)
 	name = d_make_default_arg (di, num, name);
Index: testsuite/demangle-expected
===================================================================
--- testsuite/demangle-expected	(revision 252802)
+++ testsuite/demangle-expected	(working copy)
@@ -4736,3 +4736,17 @@ __thunk_16a_$_1x
 __thunk_4294967297__$_1x
 __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
+--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}>
+--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}>
+#

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [demangler] Fix nested generic lambda
  2017-09-15 12:04 [demangler] Fix nested generic lambda Nathan Sidwell
@ 2017-09-15 16:15 ` Pedro Alves
  2017-09-15 16:52   ` Pedro Alves
  0 siblings, 1 reply; 3+ messages in thread
From: Pedro Alves @ 2017-09-15 16:15 UTC (permalink / raw)
  To: Nathan Sidwell, GCC Patches

On 09/15/2017 01:04 PM, Nathan Sidwell wrote:
> 
> 
> Pedro, would you like me to port to gdb's libiberty, or will you do a
> merge in the near future?

I wasn't planning to, but I'm doing it now.

Thanks much for the fix!

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [demangler] Fix nested generic lambda
  2017-09-15 16:15 ` Pedro Alves
@ 2017-09-15 16:52   ` Pedro Alves
  0 siblings, 0 replies; 3+ messages in thread
From: Pedro Alves @ 2017-09-15 16:52 UTC (permalink / raw)
  To: Nathan Sidwell, GCC Patches

On 09/15/2017 05:15 PM, Pedro Alves wrote:
> On 09/15/2017 01:04 PM, Nathan Sidwell wrote:
>>
>>
>> Pedro, would you like me to port to gdb's libiberty, or will you do a
>> merge in the near future?
> 
> I wasn't planning to, but I'm doing it now.
> 

Now done:
 https://sourceware.org/ml/gdb-patches/2017-09/msg00421.html

> Thanks much for the fix!

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-09-15 16:52 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-15 12:04 [demangler] Fix nested generic lambda Nathan Sidwell
2017-09-15 16:15 ` Pedro Alves
2017-09-15 16:52   ` Pedro Alves

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).