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
{
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
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
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. */
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;
::= <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;
{
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')
{
&& 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. */
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"))
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,
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')
{
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;
}
}
}
+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
}
}
+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
dpi->saved_scopes = NULL;
dpi->num_saved_scopes = 0;
+ dpi->current_template = NULL;
}
/* Free a print information structure. */
{
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.
}
dpi->modifiers = hold_dpm;
+ dpi->current_template = hold_current;
return;
}
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_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;
+ 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)
+ {
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, ' ');
if (d_last_char (dpi) == '>')
d_append_char (dpi, ' ');
d_append_char (dpi, '>');
-
- dpi->modifiers = hold_dpm;
}
}
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
--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>