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.

From-SVN: r205292
This commit is contained in:
Cary Coutant 2013-11-22 22:25:49 +00:00 committed by Cary Coutant
parent 9065ada9b5
commit 85d09f6173
4 changed files with 202 additions and 36 deletions

View File

@ -1,3 +1,26 @@
2013-11-22 Cary Coutant <ccoutant@google.com>
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.
2013-11-15 Andreas Schwab <schwab@linux-m68k.org>
* configure: Regenerate.

View File

@ -287,6 +287,19 @@ struct d_saved_scope
struct d_print_template *templates;
};
/* Checkpoint structure to allow backtracking. This holds copies
of the fields of struct d_info that need to be restored
if a trial parse needs to be backtracked over. */
struct d_info_checkpoint
{
const char *n;
int next_comp;
int next_sub;
int did_subs;
int expansion;
};
enum { D_PRINT_BUFFER_LENGTH = 256 };
struct d_print_info
{
@ -318,6 +331,8 @@ struct d_print_info
struct d_saved_scope *saved_scopes;
/* Number of saved scopes in the above array. */
int num_saved_scopes;
/* The nearest enclosing template, if any. */
const struct demangle_component *current_template;
};
#ifdef CP_DEMANGLE_DEBUG
@ -444,6 +459,10 @@ d_add_substitution (struct d_info *, struct demangle_component *);
static struct demangle_component *d_substitution (struct d_info *, int);
static void d_checkpoint (struct d_info *, struct d_info_checkpoint *);
static void d_backtrack (struct d_info *, struct d_info_checkpoint *);
static void d_growable_string_init (struct d_growable_string *, size_t);
static inline void
@ -1734,8 +1753,15 @@ d_operator_name (struct d_info *di)
if (c1 == 'v' && IS_DIGIT (c2))
return d_make_extended_operator (di, c2 - '0', d_source_name (di));
else if (c1 == 'c' && c2 == 'v')
return d_make_comp (di, DEMANGLE_COMPONENT_CAST,
cplus_demangle_type (di), NULL);
{
struct demangle_component *type;
int was_conversion = di->is_conversion;
di->is_conversion = ! di->is_expression;
type = cplus_demangle_type (di);
di->is_conversion = was_conversion;
return d_make_comp (di, DEMANGLE_COMPONENT_CAST, type, NULL);
}
else
{
/* LOW is the inclusive lower bound. */
@ -2284,13 +2310,61 @@ cplus_demangle_type (struct d_info *di)
ret = d_template_param (di);
if (d_peek_char (di) == 'I')
{
/* This is <template-template-param> <template-args>. The
<template-template-param> part is a substitution
/* This may be <template-template-param> <template-args>.
If this is the type for a conversion operator, we can
have a <template-template-param> here only by following
a derivation like this:
<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>
where the <template-args> is followed by another.
Otherwise, we must have a derivation like this:
<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>
where we need to leave the <template-args> to be processed
by d_prefix (following the <template-prefix>).
The <template-template-param> part is a substitution
candidate. */
if (! d_add_substitution (di, ret))
return NULL;
ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
d_template_args (di));
if (! di->is_conversion)
{
if (! d_add_substitution (di, ret))
return NULL;
ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
d_template_args (di));
}
else
{
struct demangle_component *args;
struct d_info_checkpoint checkpoint;
d_checkpoint (di, &checkpoint);
args = d_template_args (di);
if (d_peek_char (di) == 'I')
{
if (! d_add_substitution (di, ret))
return NULL;
ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
args);
}
else
d_backtrack (di, &checkpoint);
}
}
break;
@ -2976,8 +3050,8 @@ op_is_new_cast (struct demangle_component *op)
::= <expr-primary>
*/
static struct demangle_component *
d_expression (struct d_info *di)
static inline struct demangle_component *
d_expression_1 (struct d_info *di)
{
char peek;
@ -3005,7 +3079,7 @@ d_expression (struct d_info *di)
{
d_advance (di, 2);
return d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
d_expression (di), NULL);
d_expression_1 (di), NULL);
}
else if (peek == 'f' && d_peek_next_char (di) == 'p')
{
@ -3110,7 +3184,7 @@ d_expression (struct d_info *di)
&& d_check_char (di, '_'))
operand = d_exprlist (di, 'E');
else
operand = d_expression (di);
operand = d_expression_1 (di);
if (suffix)
/* Indicate the suffix variant for d_print_comp. */
@ -3130,7 +3204,7 @@ d_expression (struct d_info *di)
if (op_is_new_cast (op))
left = cplus_demangle_type (di);
else
left = d_expression (di);
left = d_expression_1 (di);
if (!strcmp (code, "cl"))
right = d_exprlist (di, 'E');
else if (!strcmp (code, "dt") || !strcmp (code, "pt"))
@ -3141,7 +3215,7 @@ d_expression (struct d_info *di)
right, d_template_args (di));
}
else
right = d_expression (di);
right = d_expression_1 (di);
return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op,
d_make_comp (di,
@ -3157,9 +3231,9 @@ d_expression (struct d_info *di)
if (!strcmp (code, "qu"))
{
/* ?: expression. */
first = d_expression (di);
second = d_expression (di);
third = d_expression (di);
first = d_expression_1 (di);
second = d_expression_1 (di);
third = d_expression_1 (di);
}
else if (code[0] == 'n')
{
@ -3183,7 +3257,7 @@ d_expression (struct d_info *di)
else if (d_peek_char (di) == 'i'
&& d_peek_next_char (di) == 'l')
/* initializer-list. */
third = d_expression (di);
third = d_expression_1 (di);
else
return NULL;
}
@ -3203,6 +3277,18 @@ d_expression (struct d_info *di)
}
}
static struct demangle_component *
d_expression (struct d_info *di)
{
struct demangle_component *ret;
int was_expression = di->is_expression;
di->is_expression = 1;
ret = d_expression_1 (di);
di->is_expression = was_expression;
return ret;
}
/* <expr-primary> ::= L <type> <(value) number> E
::= L <type> <(value) float> E
::= L <mangled-name> E
@ -3588,6 +3674,26 @@ d_substitution (struct d_info *di, int prefix)
}
}
static void
d_checkpoint (struct d_info *di, struct d_info_checkpoint *checkpoint)
{
checkpoint->n = di->n;
checkpoint->next_comp = di->next_comp;
checkpoint->next_sub = di->next_sub;
checkpoint->did_subs = di->did_subs;
checkpoint->expansion = di->expansion;
}
static void
d_backtrack (struct d_info *di, struct d_info_checkpoint *checkpoint)
{
di->n = checkpoint->n;
di->next_comp = checkpoint->next_comp;
di->next_sub = checkpoint->next_sub;
di->did_subs = checkpoint->did_subs;
di->expansion = checkpoint->expansion;
}
/* Initialize a growable string. */
static void
@ -3684,6 +3790,7 @@ d_print_init (struct d_print_info *dpi, demangle_callbackref callback,
dpi->saved_scopes = NULL;
dpi->num_saved_scopes = 0;
dpi->current_template = NULL;
}
/* Free a print information structure. */
@ -4165,6 +4272,12 @@ d_print_comp (struct d_print_info *dpi, int options,
{
struct d_print_mod *hold_dpm;
struct demangle_component *dcl;
const struct demangle_component *hold_current;
/* This template may need to be referenced by a cast operator
contained in its subtree. */
hold_current = dpi->current_template;
dpi->current_template = dc;
/* Don't push modifiers into a template definition. Doing so
could give the wrong definition for a template argument.
@ -4201,6 +4314,7 @@ d_print_comp (struct d_print_info *dpi, int options,
}
dpi->modifiers = hold_dpm;
dpi->current_template = hold_current;
return;
}
@ -5418,28 +5532,32 @@ static void
d_print_cast (struct d_print_info *dpi, int options,
const struct demangle_component *dc)
{
if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE)
d_print_comp (dpi, options, d_left (dc));
else
struct d_print_template dpt;
/* For a cast operator, we need the template parameters from
the enclosing template in scope for processing the type. */
if (dpi->current_template != NULL)
{
struct d_print_mod *hold_dpm;
struct d_print_template dpt;
/* It appears that for a templated cast operator, we need to put
the template parameters in scope for the operator name, but
not for the parameters. The effect is that we need to handle
the template printing here. */
hold_dpm = dpi->modifiers;
dpi->modifiers = NULL;
dpt.next = dpi->templates;
dpi->templates = &dpt;
dpt.template_decl = d_left (dc);
dpt.template_decl = dpi->current_template;
}
if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE)
{
d_print_comp (dpi, options, d_left (dc));
if (dpi->current_template != NULL)
dpi->templates = dpt.next;
}
else
{
d_print_comp (dpi, options, d_left (d_left (dc)));
dpi->templates = dpt.next;
/* For a templated cast operator, we need to remove the template
parameters from scope after printing the operator name,
so we need to handle the template printing here. */
if (dpi->current_template != NULL)
dpi->templates = dpt.next;
if (d_last_char (dpi) == '<')
d_append_char (dpi, ' ');
@ -5450,8 +5568,6 @@ d_print_cast (struct d_print_info *dpi, int options,
if (d_last_char (dpi) == '>')
d_append_char (dpi, ' ');
d_append_char (dpi, '>');
dpi->modifiers = hold_dpm;
}
}
@ -5484,6 +5600,8 @@ cplus_demangle_init_info (const char *mangled, int options, size_t len,
di->last_name = NULL;
di->expansion = 0;
di->is_expression = 0;
di->is_conversion = 0;
}
/* Internal implementation for the demangler. If MANGLED is a g++ v3 ABI

View File

@ -122,6 +122,11 @@ struct d_info
mangled name to the demangled name, such as standard
substitutions and builtin types. */
int expansion;
/* Non-zero if we are parsing an expression. */
int is_expression;
/* Non-zero if we are parsing the type operand of a conversion
operator, but not when in an expression. */
int is_conversion;
};
/* To avoid running past the ending '\0', don't:

View File

@ -4297,3 +4297,23 @@ void f<int>()
--format=gnu-v3
_ZSt7forwardIRN1x14refobjiteratorINS0_3refINS0_4mime30multipart_section_processorObjIZ15get_body_parserIZZN14mime_processor21make_section_iteratorERKNS2_INS3_10sectionObjENS0_10ptrrefBaseEEEbENKUlvE_clEvEUlSB_bE_ZZNS6_21make_section_iteratorESB_bENKSC_clEvEUlSB_E0_ENS1_INS2_INS0_20outputrefiteratorObjIiEES8_EEEERKSsSB_OT_OT0_EUlmE_NS3_32make_multipart_default_discarderISP_EEEES8_EEEEEOT_RNSt16remove_referenceISW_E4typeE
x::refobjiterator<x::ref<x::mime::multipart_section_processorObj<x::refobjiterator<x::ref<x::outputrefiteratorObj<int>, x::ptrrefBase> > get_body_parser<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}>(std::string const&, x::ref<x::mime::sectionObj, x::ptrrefBase> const&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}&&)::{lambda(unsigned long)#1}, x::mime::make_multipart_default_discarder<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&> >, x::ptrrefBase> >& std::forward<x::refobjiterator<x::ref<x::mime::multipart_section_processorObj<x::refobjiterator<x::ref<x::outputrefiteratorObj<int>, x::ptrrefBase> > get_body_parser<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}>(std::string const&, x::ref<x::mime::sectionObj, x::ptrrefBase> const&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}&&)::{lambda(unsigned long)#1}, x::mime::make_multipart_default_discarder<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&> >, x::ptrrefBase> >&>(std::remove_reference<x::mime::multipart_section_processorObj<x::refobjiterator<x::ref<x::outputrefiteratorObj<int>, x::ptrrefBase> > get_body_parser<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}>(std::string const&, x::ref<x::mime::sectionObj, x::ptrrefBase> const&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}&&)::{lambda(unsigned long)#1}, x::mime::make_multipart_default_discarder<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&> > >::type&)
#
--format=gnu-v3 --no-params
_ZNK7strings8internal8SplitterINS_9delimiter5AnyOfENS_9SkipEmptyEEcvT_ISt6vectorI12basic_stringIcSt11char_traitsIcESaIcEESaISD_EEvEEv
strings::internal::Splitter<strings::delimiter::AnyOf, strings::SkipEmpty>::operator std::vector<basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<basic_string<char, std::char_traits<char>, std::allocator<char> > > ><std::vector<basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<basic_string<char, std::char_traits<char>, std::allocator<char> > > >, void>() const
strings::internal::Splitter<strings::delimiter::AnyOf, strings::SkipEmpty>::operator std::vector<basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<basic_string<char, std::char_traits<char>, std::allocator<char> > > ><std::vector<basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<basic_string<char, std::char_traits<char>, std::allocator<char> > > >, void>
#
--format=gnu-v3 --no-params
_ZN1AcvT_I1CEEv
A::operator C<C>()
A::operator C<C>
#
--format=gnu-v3 --no-params
_ZN1AcvPT_I1CEEv
A::operator C*<C>()
A::operator C*<C>
#
--format=gnu-v3 --no-params
_ZN1AcvT_IiEI1CEEv
A::operator C<int><C>()
A::operator C<int><C>