public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug other/59195] New: C++ demangler handles conversion operator incorrectly
@ 2013-11-19 18:53 ccoutant at gcc dot gnu.org
  2013-11-19 18:56 ` [Bug other/59195] " ccoutant at gcc dot gnu.org
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: ccoutant at gcc dot gnu.org @ 2013-11-19 18:53 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59195

            Bug ID: 59195
           Summary: C++ demangler handles conversion operator incorrectly
           Product: gcc
           Version: 4.9.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: other
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ccoutant at gcc dot gnu.org

Consider this simple source:

  struct C {
    C(int i_) : i(i_) { }
    int i;
  };

  struct A {
    A() : i(0) { }
    template <typename U>
    explicit operator U();
    int i;
  };

  void foo()
  {
    A ai;
    C c = (C)ai;
  }

The conversion operator in A mangles to "_ZN1AcvT_I1CEEv", which
demangles to:

  A::operator C<C>()

(I think this would be better as "A::operator C()", but let's
leave that aside for now.)

That looks OK, but not if you dig deeper. The demangler is
parsing this name as follows:

  typed name
    qualified name
      name 'A'
      cast
    template
      template parameter 0
      template argument list
        name 'C'
    function type
      argument list
  A::operator C<C>()

It's parsing the "T_" as a <template-template-param>, not a
<template-param>. It should really be parsing it as:

  typed name
    template
      qualified name
    name 'A'
    cast
      template parameter 0
      template argument list
    name 'C'
    function type
      argument list
  A::operator C<C>()

The template argument list actually belongs with the
<qualified-name>, not with the template parameter.

The basic problem is an ambiguity in the grammar for mangled
names. Consider the following two derivations:

  (1) <nested-name>
      -> <template-prefix> <template-args>
      -> <prefix> <template-unqualified-name> <template-args>
      -> <unqualified-name> <template-unqualified-name>
                                                   <template-args>
      -> <source-name> <template-unqualified-name> <template-args>
      -> <source-name> <operator-name> <template-args>
      -> <source-name> cv <type> <template-args>
      -> <source-name> cv <template-template-param>
                                   <template-args> <template-args>

  (2) <nested-name>
      -> <template-prefix> <template-args>
      -> <prefix> <template-unqualified-name> <template-args>
      -> <unqualified-name> <template-unqualified-name>
                                                   <template-args>
      -> <source-name> <template-unqualified-name> <template-args>
      -> <source-name> <operator-name> <template-args>
      -> <source-name> cv <type> <template-args>
      -> <source-name> cv <template-param> <template-args>

When you get to the "T_", there's no way to know if it's a
<template-param> or a <template-template-param>. The parser in
cp-demangle.c, in cplus_demangle_type, looks ahead to
disambiguate the two. If it sees an 'I', it assumes that it's a
<template-template-param>, and it greedily consumes the
<template-args>.

In this particular case, it's wrong, but it gets the right answer
because of a hack in d_print_cast, which takes the template
arguments under the cast operator, and places them in scope
before resolving the "T_" reference.

It doesn't take much to break that hack, though. Let's throw in a
pointer:

  struct C {
    C(int i_) : i(i_) { }
    int i;
  };

  struct A {
    A() : i(0) { }
    template <typename U>
    explicit operator U*();
    int i;
  };

  void foo()
  {
    A ai;
    C* c = (C*)ai;
  }

Now we get the mangled name "_ZN1AcvPT_I1CEEv", which the
demangler fails on:

  typed name
    qualified name
      name 'A'
      cast
    pointer
      template
        template parameter 0
        template argument list
          name 'C'
    function type
      argument list
  Failed: _ZN1AcvPT_I1CEEv

This name ought to be parsed as follows:

  typed name
    template
      qualified name
    name 'A'
    cast
      pointer
        template parameter 0
      template argument list
    name 'C'
    function type
      argument list
  A::operator C*<C>()

(This incorrect parsing can also lead to some other subtle types
of failures, because substitutions can be numbered in the wrong
order. See the long example that started me on this investigation
at the end.)

Now let's add a real template template parameter:

  template <typename T>
  struct C {
    C(T i_) : i(i_) { }
    T i;
  };

  struct A {
    A() : i(0) { }
    template <template<typename U> class V>
    operator V<int>();
    int i;
  };

  void foo()
  {
    A ai;
    C<int> c = (C<int>)ai;
  }

The conversion operator is now "_ZN1AcvT_IiEI1CEEv", and the
demangler gives us this:

  typed name
    template
      qualified name
    name 'A'
    cast
      template
        template parameter 0
        template argument list
          builtin type int
      template argument list
    name 'C'
    function type
      argument list
  A::operator int<int><C>()

The derivation is actually correct this time, because we really
do have a <template-template-param>, but the hack in d_print_cast
causes it to substitute the wrong type for "T_".

I'm pretty sure that the ambiguity can be resolved by context.
Note that if we have a <template-template-param>, the
<template-args> that go with it are followed by another set of
<template-args> that go with the <template-prefix> in the second
step of the derivation. (This is only true if we're parsing a
conversion operator that derives from <nested-name>; if it's a
conversion operator that's part of an <expression>, the presence
of an 'I' should always indicate that we're looking at a
<template-template-param>.)

I've got a patch that solves this with a little backtracking. If
we're in a conversion operator that's not part of an
<expression>, and we see an 'I', it checkpoints the d_info
structure, does a trial parse of <template-args>, then looks for
another 'I'. If there isn't one, it backtracks and returns a
<template-param>, leaving the <template-args> for d_prefix to
parse.

When printing a conversion operator, in d_print_cast, if the
operator is derived from a <template>, we need to place that
template in scope so that the <template-param> can look up the
correct type. We can't just add it to the stack of templates,
though, since that's only applicable when printing the type of a
function whose name is a template.

Here's the long example that started me down this path:

 
_ZNK7strings8internal8SplitterINS_9delimiter5AnyOfENS_9SkipEmptyEEcvT_ISt6vectorI12basic_stringIcSt11char_traitsIcESaIcEESaISD_EEvEEv

The demangler fails to parse this string, because the "SD_" near
the end is asking for the 15th substitution, but at that point it
has only registered 14 substitutions. That happened because it
greedily consumed the <template-args> that follow "cvT_", and
hadn't yet registered the substitution for the conversion
operator (which derives from <prefix>). Any substitutions that
are contained in the <template-args> will be off by one as a
result.


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

* [Bug other/59195] C++ demangler handles conversion operator incorrectly
  2013-11-19 18:53 [Bug other/59195] New: C++ demangler handles conversion operator incorrectly ccoutant at gcc dot gnu.org
@ 2013-11-19 18:56 ` ccoutant at gcc dot gnu.org
  2013-11-22 22:25 ` ccoutant at gcc dot gnu.org
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: ccoutant at gcc dot gnu.org @ 2013-11-19 18:56 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59195

Cary Coutant <ccoutant at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |ASSIGNED
   Last reconfirmed|                            |2013-11-19
           Assignee|unassigned at gcc dot gnu.org      |ccoutant at gcc dot gnu.org
     Ever confirmed|0                           |1

--- Comment #1 from Cary Coutant <ccoutant at gcc dot gnu.org> ---
Created attachment 31253
  --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=31253&action=edit
Proposed patch


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

* [Bug other/59195] C++ demangler handles conversion operator incorrectly
  2013-11-19 18:53 [Bug other/59195] New: C++ demangler handles conversion operator incorrectly ccoutant at gcc dot gnu.org
  2013-11-19 18:56 ` [Bug other/59195] " ccoutant at gcc dot gnu.org
@ 2013-11-22 22:25 ` ccoutant at gcc dot gnu.org
  2014-02-25 19:58 ` ccoutant at gcc dot gnu.org
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: ccoutant at gcc dot gnu.org @ 2013-11-22 22:25 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59195

--- Comment #2 from Cary Coutant <ccoutant at gcc dot gnu.org> ---
Author: ccoutant
Date: Fri Nov 22 22:25:49 2013
New Revision: 205292

URL: http://gcc.gnu.org/viewcvs?rev=205292&root=gcc&view=rev
Log:
Fix demangler to handle conversion operators correctly.

libiberty/
    PR other/59195
    * cp-demangle.c (struct d_info_checkpoint): New struct.
    (struct d_print_info): Add current_template field.
    (d_operator_name): Set flag when processing a conversion
    operator.
    (cplus_demangle_type): When processing <template-args> for
    a conversion operator, backtrack if necessary.
    (d_expression_1): Renamed from d_expression.
    (d_expression): New wrapper around d_expression_1.
    (d_checkpoint): New function.
    (d_backtrack): New function.
    (d_print_init): Initialize current_template.
    (d_print_comp): Set current_template.
    (d_print_cast): Put current_template in scope for
    printing conversion operator name.
    (cplus_demangle_init_info): Initialize is_expression and
    is_conversion.
    * cp-demangle.h (struct d_info): Add is_expression and
    is_conversion fields.
    * testsuite/demangle-expected: New test cases.

Modified:
    trunk/libiberty/ChangeLog
    trunk/libiberty/cp-demangle.c
    trunk/libiberty/cp-demangle.h
    trunk/libiberty/testsuite/demangle-expected


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

* [Bug other/59195] C++ demangler handles conversion operator incorrectly
  2013-11-19 18:53 [Bug other/59195] New: C++ demangler handles conversion operator incorrectly ccoutant at gcc dot gnu.org
  2013-11-19 18:56 ` [Bug other/59195] " ccoutant at gcc dot gnu.org
  2013-11-22 22:25 ` ccoutant at gcc dot gnu.org
@ 2014-02-25 19:58 ` ccoutant at gcc dot gnu.org
  2014-05-26 14:04 ` palves at redhat dot com
  2014-05-26 14:05 ` palves at redhat dot com
  4 siblings, 0 replies; 6+ messages in thread
From: ccoutant at gcc dot gnu.org @ 2014-02-25 19:58 UTC (permalink / raw)
  To: gcc-bugs

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59195

Cary Coutant <ccoutant at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|ASSIGNED                    |RESOLVED
         Resolution|---                         |FIXED

--- Comment #3 from Cary Coutant <ccoutant at gcc dot gnu.org> ---
Fixed at r205292.


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

* [Bug other/59195] C++ demangler handles conversion operator incorrectly
  2013-11-19 18:53 [Bug other/59195] New: C++ demangler handles conversion operator incorrectly ccoutant at gcc dot gnu.org
                   ` (2 preceding siblings ...)
  2014-02-25 19:58 ` ccoutant at gcc dot gnu.org
@ 2014-05-26 14:04 ` palves at redhat dot com
  2014-05-26 14:05 ` palves at redhat dot com
  4 siblings, 0 replies; 6+ messages in thread
From: palves at redhat dot com @ 2014-05-26 14:04 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59195

Pedro Alves <palves at redhat dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |palves at redhat dot com

--- Comment #4 from Pedro Alves <palves at redhat dot com> ---
This caused bug 61321.


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

* [Bug other/59195] C++ demangler handles conversion operator incorrectly
  2013-11-19 18:53 [Bug other/59195] New: C++ demangler handles conversion operator incorrectly ccoutant at gcc dot gnu.org
                   ` (3 preceding siblings ...)
  2014-05-26 14:04 ` palves at redhat dot com
@ 2014-05-26 14:05 ` palves at redhat dot com
  4 siblings, 0 replies; 6+ messages in thread
From: palves at redhat dot com @ 2014-05-26 14:05 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59195

--- Comment #5 from Pedro Alves <palves at redhat dot com> ---
Likely bug 61233 too.


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

end of thread, other threads:[~2014-05-26 14:05 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-19 18:53 [Bug other/59195] New: C++ demangler handles conversion operator incorrectly ccoutant at gcc dot gnu.org
2013-11-19 18:56 ` [Bug other/59195] " ccoutant at gcc dot gnu.org
2013-11-22 22:25 ` ccoutant at gcc dot gnu.org
2014-02-25 19:58 ` ccoutant at gcc dot gnu.org
2014-05-26 14:04 ` palves at redhat dot com
2014-05-26 14:05 ` palves at redhat dot com

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).