diff options
author | Yabin Cui <yabinc@google.com> | 2014-11-25 00:26:19 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-11-25 00:26:21 +0000 |
commit | 9290490959af27ad6815a7d660f1d98509c370e6 (patch) | |
tree | 752a5cb67273b06ead1cdb886d3bf290e108d5ec | |
parent | 9241386b62c353302c2f9eccda0672685b252b4d (diff) | |
parent | 23917bc01363c324da42d8dd57a83194844ff206 (diff) | |
download | gcc-demangle-9290490959af27ad6815a7d660f1d98509c370e6.tar.gz |
-rw-r--r-- | Android.mk | 8 | ||||
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | cp-demangle.c | 1541 | ||||
-rw-r--r-- | cp-demangle.h | 5 | ||||
-rw-r--r-- | demangle.h | 53 | ||||
-rw-r--r-- | demangle_test.cpp | 74 | ||||
-rw-r--r-- | test.c | 21 |
7 files changed, 1413 insertions, 295 deletions
@@ -60,20 +60,20 @@ include $(BUILD_HOST_STATIC_LIBRARY) include $(CLEAR_VARS) -LOCAL_SRC_FILES := test.c +LOCAL_SRC_FILES := demangle_test.cpp LOCAL_SHARED_LIBRARIES := libgccdemangle LOCAL_MODULE := gccdemangle_test LOCAL_MODULE_TAGS := optional -include $(BUILD_EXECUTABLE) +include $(BUILD_NATIVE_TEST) ########################## include $(CLEAR_VARS) -LOCAL_SRC_FILES := test.c +LOCAL_SRC_FILES := demangle_test.cpp LOCAL_SHARED_LIBRARIES := libgccdemangle LOCAL_MODULE := gccdemangle_test LOCAL_MODULE_TAGS := optional -include $(BUILD_HOST_EXECUTABLE) +include $(BUILD_HOST_NATIVE_TEST) @@ -1,3 +1,9 @@ +2014-11-24 + * cp-demangle.c: Update from FSF branches/google/gcc-4_9/libiberty + * demangle.h: Likewise + * cp-demangle.h: Likewise + * demangle_test.cpp: move test.c to gtest test units. + 2011-11-08 Jing Yu <jingyu@google.com> * cp-demangle.c: Remove #include of ansidecl.h and libiberty.h diff --git a/cp-demangle.c b/cp-demangle.c index 01d0227..0949eb3 100644 --- a/cp-demangle.c +++ b/cp-demangle.c @@ -1,5 +1,5 @@ /* Demangler for g++ V3 ABI. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014 Free Software Foundation, Inc. Written by Ian Lance Taylor <ian@wasabisystems.com>. @@ -275,11 +275,34 @@ struct d_growable_string int allocation_failure; }; +/* A demangle component and some scope captured when it was first + traversed. */ + +struct d_saved_scope +{ + /* The component whose scope this is. */ + const struct demangle_component *container; + /* The list of templates, if any, that was current when this + scope was captured. */ + 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 { - /* The options passed to the demangler. */ - int options; /* Fixed-length allocated buffer for demangled data, flushed to the callback with a NUL termination once full. */ char buf[D_PRINT_BUFFER_LENGTH]; @@ -304,6 +327,20 @@ struct d_print_info int pack_index; /* Number of d_print_flush calls so far. */ unsigned long int flush_count; + /* Array of saved scopes for evaluating substitutions. */ + struct d_saved_scope *saved_scopes; + /* Index of the next unused saved scope in the above array. */ + int next_saved_scope; + /* Number of saved scopes in the above array. */ + int num_saved_scopes; + /* Array of templates for saving into scopes. */ + struct d_print_template *copy_templates; + /* Index of the next unused copy template in the above array. */ + int next_copy_template; + /* Number of copy templates in the above array. */ + int num_copy_templates; + /* The nearest enclosing template, if any. */ + const struct demangle_component *current_template; }; #ifdef CP_DEMANGLE_DEBUG @@ -384,6 +421,9 @@ static struct demangle_component ** d_cv_qualifiers (struct d_info *, struct demangle_component **, int); static struct demangle_component * +d_ref_qualifier (struct d_info *, struct demangle_component *); + +static struct demangle_component * d_function_type (struct d_info *); static struct demangle_component * @@ -419,11 +459,18 @@ static struct demangle_component *d_lambda (struct d_info *); static struct demangle_component *d_unnamed_type (struct d_info *); +static struct demangle_component * +d_clone_suffix (struct d_info *, struct demangle_component *); + static int 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 @@ -436,7 +483,8 @@ static void d_growable_string_callback_adapter (const char *, size_t, void *); static void -d_print_init (struct d_print_info *, int, demangle_callbackref, void *); +d_print_init (struct d_print_info *, demangle_callbackref, void *, + const struct demangle_component *); static inline void d_print_error (struct d_print_info *); @@ -454,32 +502,34 @@ static inline void d_append_string (struct d_print_info *, const char *); static inline char d_last_char (struct d_print_info *); static void -d_print_comp (struct d_print_info *, const struct demangle_component *); +d_print_comp (struct d_print_info *, int, const struct demangle_component *); static void d_print_java_identifier (struct d_print_info *, const char *, int); static void -d_print_mod_list (struct d_print_info *, struct d_print_mod *, int); +d_print_mod_list (struct d_print_info *, int, struct d_print_mod *, int); static void -d_print_mod (struct d_print_info *, const struct demangle_component *); +d_print_mod (struct d_print_info *, int, const struct demangle_component *); static void -d_print_function_type (struct d_print_info *, +d_print_function_type (struct d_print_info *, int, const struct demangle_component *, struct d_print_mod *); static void -d_print_array_type (struct d_print_info *, +d_print_array_type (struct d_print_info *, int, const struct demangle_component *, struct d_print_mod *); static void -d_print_expr_op (struct d_print_info *, const struct demangle_component *); +d_print_expr_op (struct d_print_info *, int, const struct demangle_component *); -static void -d_print_cast (struct d_print_info *, const struct demangle_component *); +static void d_print_cast (struct d_print_info *, int, + const struct demangle_component *); +static void d_print_conversion (struct d_print_info *, int, + const struct demangle_component *); static int d_demangle_callback (const char *, int, demangle_callbackref, void *); @@ -507,6 +557,11 @@ d_dump (struct demangle_component *dc, int indent) case DEMANGLE_COMPONENT_NAME: printf ("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s); return; + case DEMANGLE_COMPONENT_TAGGED_NAME: + printf ("tagged name\n"); + d_dump (dc->u.s_binary.left, indent + 2); + d_dump (dc->u.s_binary.right, indent + 2); + return; case DEMANGLE_COMPONENT_TEMPLATE_PARAM: printf ("template parameter %ld\n", dc->u.s_number.number); return; @@ -584,6 +639,12 @@ d_dump (struct demangle_component *dc, int indent) case DEMANGLE_COMPONENT_HIDDEN_ALIAS: printf ("hidden alias\n"); break; + case DEMANGLE_COMPONENT_TRANSACTION_CLONE: + printf ("transaction clone\n"); + break; + case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE: + printf ("non-transaction clone\n"); + break; case DEMANGLE_COMPONENT_RESTRICT: printf ("restrict\n"); break; @@ -602,6 +663,12 @@ d_dump (struct demangle_component *dc, int indent) case DEMANGLE_COMPONENT_CONST_THIS: printf ("const this\n"); break; + case DEMANGLE_COMPONENT_REFERENCE_THIS: + printf ("reference this\n"); + break; + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: + printf ("rvalue reference this\n"); + break; case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: printf ("vendor type qualifier\n"); break; @@ -641,9 +708,18 @@ d_dump (struct demangle_component *dc, int indent) case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: printf ("template argument list\n"); break; + case DEMANGLE_COMPONENT_INITIALIZER_LIST: + printf ("initializer list\n"); + break; case DEMANGLE_COMPONENT_CAST: printf ("cast\n"); break; + case DEMANGLE_COMPONENT_CONVERSION: + printf ("conversion operator\n"); + break; + case DEMANGLE_COMPONENT_NULLARY: + printf ("nullary operator\n"); + break; case DEMANGLE_COMPONENT_UNARY: printf ("unary operator\n"); break; @@ -683,6 +759,20 @@ d_dump (struct demangle_component *dc, int indent) case DEMANGLE_COMPONENT_PACK_EXPANSION: printf ("pack expansion\n"); break; + case DEMANGLE_COMPONENT_TLS_INIT: + printf ("tls init function\n"); + break; + case DEMANGLE_COMPONENT_TLS_WRAPPER: + printf ("tls wrapper function\n"); + break; + case DEMANGLE_COMPONENT_DEFAULT_ARG: + printf ("default argument %d\n", dc->u.s_unary_num.num); + d_dump (dc->u.s_unary_num.sub, indent+2); + return; + case DEMANGLE_COMPONENT_LAMBDA: + printf ("lambda %d\n", dc->u.s_unary_num.num); + d_dump (dc->u.s_unary_num.sub, indent+2); + return; } d_dump (d_left (dc), indent + 2); @@ -731,7 +821,7 @@ cplus_demangle_fill_ctor (struct demangle_component *p, if (p == NULL || name == NULL || (int) kind < gnu_v3_complete_object_ctor - || (int) kind > gnu_v3_complete_object_allocating_ctor) + || (int) kind > gnu_v3_object_ctor_group) return 0; p->type = DEMANGLE_COMPONENT_CTOR; p->u.s_ctor.kind = kind; @@ -750,7 +840,7 @@ cplus_demangle_fill_dtor (struct demangle_component *p, if (p == NULL || name == NULL || (int) kind < gnu_v3_deleting_dtor - || (int) kind > gnu_v3_base_object_dtor) + || (int) kind > gnu_v3_object_dtor_group) return 0; p->type = DEMANGLE_COMPONENT_DTOR; p->u.s_dtor.kind = kind; @@ -790,6 +880,7 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_QUAL_NAME: case DEMANGLE_COMPONENT_LOCAL_NAME: case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_TAGGED_NAME: case DEMANGLE_COMPONENT_TEMPLATE: case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: @@ -799,11 +890,11 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_BINARY_ARGS: case DEMANGLE_COMPONENT_TRINARY: case DEMANGLE_COMPONENT_TRINARY_ARG1: - case DEMANGLE_COMPONENT_TRINARY_ARG2: case DEMANGLE_COMPONENT_LITERAL: case DEMANGLE_COMPONENT_LITERAL_NEG: case DEMANGLE_COMPONENT_COMPOUND_NAME: case DEMANGLE_COMPONENT_VECTOR_TYPE: + case DEMANGLE_COMPONENT_CLONE: if (left == NULL || right == NULL) return NULL; break; @@ -819,8 +910,12 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_COVARIANT_THUNK: case DEMANGLE_COMPONENT_JAVA_CLASS: case DEMANGLE_COMPONENT_GUARD: + case DEMANGLE_COMPONENT_TLS_INIT: + case DEMANGLE_COMPONENT_TLS_WRAPPER: case DEMANGLE_COMPONENT_REFTEMP: case DEMANGLE_COMPONENT_HIDDEN_ALIAS: + case DEMANGLE_COMPONENT_TRANSACTION_CLONE: + case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE: case DEMANGLE_COMPONENT_POINTER: case DEMANGLE_COMPONENT_REFERENCE: case DEMANGLE_COMPONENT_RVALUE_REFERENCE: @@ -828,11 +923,14 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_IMAGINARY: case DEMANGLE_COMPONENT_VENDOR_TYPE: case DEMANGLE_COMPONENT_CAST: + case DEMANGLE_COMPONENT_CONVERSION: case DEMANGLE_COMPONENT_JAVA_RESOURCE: case DEMANGLE_COMPONENT_DECLTYPE: case DEMANGLE_COMPONENT_PACK_EXPANSION: case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: + case DEMANGLE_COMPONENT_NULLARY: + case DEMANGLE_COMPONENT_TRINARY_ARG2: if (left == NULL) return NULL; break; @@ -840,6 +938,7 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, /* This needs a right parameter, but the left parameter can be empty. */ case DEMANGLE_COMPONENT_ARRAY_TYPE: + case DEMANGLE_COMPONENT_INITIALIZER_LIST: if (right == NULL) return NULL; break; @@ -853,6 +952,8 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_RESTRICT_THIS: case DEMANGLE_COMPONENT_VOLATILE_THIS: case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_REFERENCE_THIS: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: case DEMANGLE_COMPONENT_ARGLIST: case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: break; @@ -1036,7 +1137,7 @@ d_make_sub (struct d_info *di, const char *name, int len) return p; } -/* <mangled-name> ::= _Z <encoding> +/* <mangled-name> ::= _Z <encoding> [<clone-suffix>]* TOP_LEVEL is non-zero when called at the top level. */ @@ -1044,6 +1145,8 @@ CP_STATIC_IF_GLIBCPP_V3 struct demangle_component * cplus_demangle_mangled_name (struct d_info *di, int top_level) { + struct demangle_component *p; + if (! d_check_char (di, '_') /* Allow missing _ if not at toplevel to work around a bug in G++ abi-version=2 mangling; see the comment in @@ -1052,7 +1155,18 @@ cplus_demangle_mangled_name (struct d_info *di, int top_level) return NULL; if (! d_check_char (di, 'Z')) return NULL; - return d_encoding (di, top_level); + p = d_encoding (di, top_level); + + /* If at top level and parsing parameters, check for a clone + suffix. */ + if (top_level && (di->options & DMGL_PARAMS) != 0) + while (d_peek_char (di) == '.' + && (IS_LOWER (d_peek_next_char (di)) + || d_peek_next_char (di) == '_' + || IS_DIGIT (d_peek_next_char (di)))) + p = d_clone_suffix (di, p); + + return p; } /* Return whether a function should have a return type. The argument @@ -1078,6 +1192,8 @@ has_return_type (struct demangle_component *dc) case DEMANGLE_COMPONENT_RESTRICT_THIS: case DEMANGLE_COMPONENT_VOLATILE_THIS: case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_REFERENCE_THIS: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: return has_return_type (d_left (dc)); } } @@ -1099,7 +1215,7 @@ is_ctor_dtor_or_conversion (struct demangle_component *dc) return is_ctor_dtor_or_conversion (d_right (dc)); case DEMANGLE_COMPONENT_CTOR: case DEMANGLE_COMPONENT_DTOR: - case DEMANGLE_COMPONENT_CAST: + case DEMANGLE_COMPONENT_CONVERSION: return 1; } } @@ -1133,7 +1249,9 @@ d_encoding (struct d_info *di, int top_level) 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_CONST_THIS + || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS + || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS) dc = d_left (dc); /* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then @@ -1147,7 +1265,9 @@ d_encoding (struct d_info *di, int top_level) dcr = d_right (dc); while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS || dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS - || dcr->type == DEMANGLE_COMPONENT_CONST_THIS) + || dcr->type == DEMANGLE_COMPONENT_CONST_THIS + || dcr->type == DEMANGLE_COMPONENT_REFERENCE_THIS + || dcr->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS) dcr = d_left (dcr); dc->u.s_binary.right = dcr; } @@ -1163,6 +1283,23 @@ d_encoding (struct d_info *di, int top_level) } } +/* <tagged-name> ::= <name> B <source-name> */ + +static struct demangle_component * +d_abi_tags (struct d_info *di, struct demangle_component *dc) +{ + char peek; + while (peek = d_peek_char (di), + peek == 'B') + { + struct demangle_component *tag; + d_advance (di, 1); + tag = d_source_name (di); + dc = d_make_comp (di, DEMANGLE_COMPONENT_TAGGED_NAME, dc, tag); + } + return dc; +} + /* <name> ::= <nested-name> ::= <unscoped-name> ::= <unscoped-template-name> <template-args> @@ -1189,7 +1326,6 @@ d_name (struct d_info *di) case 'Z': return d_local_name (di); - case 'L': case 'U': return d_unqualified_name (di); @@ -1236,6 +1372,7 @@ d_name (struct d_info *di) return dc; } + case 'L': default: dc = d_unqualified_name (di); if (d_peek_char (di) == 'I') @@ -1252,8 +1389,8 @@ d_name (struct d_info *di) } } -/* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E - ::= N [<CV-qualifiers>] <template-prefix> <template-args> E +/* <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E + ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E */ static struct demangle_component * @@ -1261,6 +1398,7 @@ d_nested_name (struct d_info *di) { struct demangle_component *ret; struct demangle_component **pret; + struct demangle_component *rqual; if (! d_check_char (di, 'N')) return NULL; @@ -1269,10 +1407,20 @@ d_nested_name (struct d_info *di) if (pret == NULL) return NULL; + /* Parse the ref-qualifier now and then attach it + once we have something to attach it to. */ + rqual = d_ref_qualifier (di, NULL); + *pret = d_prefix (di); if (*pret == NULL) return NULL; + if (rqual) + { + d_left (rqual) = ret; + ret = rqual; + } + if (! d_check_char (di, 'E')) return NULL; @@ -1282,6 +1430,7 @@ d_nested_name (struct d_info *di) /* <prefix> ::= <prefix> <unqualified-name> ::= <template-prefix> <template-args> ::= <template-param> + ::= <decltype> ::= ::= <substitution> @@ -1310,10 +1459,19 @@ d_prefix (struct d_info *di) <template-param> here. */ comb_type = DEMANGLE_COMPONENT_QUAL_NAME; - if (IS_DIGIT (peek) + if (peek == 'D') + { + char peek2 = d_peek_next_char (di); + if (peek2 == 'T' || peek2 == 't') + /* Decltype. */ + dc = cplus_demangle_type (di); + else + /* Destructor name. */ + dc = d_unqualified_name (di); + } + else if (IS_DIGIT (peek) || IS_LOWER (peek) || peek == 'C' - || peek == 'D' || peek == 'U' || peek == 'L') dc = d_unqualified_name (di); @@ -1367,26 +1525,27 @@ d_prefix (struct d_info *di) static struct demangle_component * d_unqualified_name (struct d_info *di) { + struct demangle_component *ret; char peek; peek = d_peek_char (di); if (IS_DIGIT (peek)) - return d_source_name (di); + ret = d_source_name (di); else if (IS_LOWER (peek)) { - struct demangle_component *ret; - ret = d_operator_name (di); if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR) - di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2; - return ret; + { + di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2; + if (!strcmp (ret->u.s_operator.op->code, "li")) + ret = d_make_comp (di, DEMANGLE_COMPONENT_UNARY, ret, + d_source_name (di)); + } } else if (peek == 'C' || peek == 'D') - return d_ctor_dtor_name (di); + ret = d_ctor_dtor_name (di); else if (peek == 'L') { - struct demangle_component * ret; - d_advance (di, 1); ret = d_source_name (di); @@ -1394,22 +1553,27 @@ d_unqualified_name (struct d_info *di) return NULL; if (! d_discriminator (di)) return NULL; - return ret; } else if (peek == 'U') { switch (d_peek_next_char (di)) { case 'l': - return d_lambda (di); + ret = d_lambda (di); + break; case 't': - return d_unnamed_type (di); + ret = d_unnamed_type (di); + break; default: return NULL; } } else return NULL; + + if (d_peek_char (di) == 'B') + ret = d_abi_tags (di, ret); + return ret; } /* <source-name> ::= <(positive length) number> <identifier> */ @@ -1521,7 +1685,8 @@ d_identifier (struct d_info *di, int len) /* operator_name ::= many different two character encodings. ::= cv <type> ::= v <digit> <source-name> -*/ + + This list is sorted for binary search. */ #define NL(s) s, (sizeof s) - 1 @@ -1533,23 +1698,30 @@ const struct demangle_operator_info cplus_demangle_operators[] = { "aa", NL ("&&"), 2 }, { "ad", NL ("&"), 1 }, { "an", NL ("&"), 2 }, + { "at", NL ("alignof "), 1 }, + { "az", NL ("alignof "), 1 }, + { "cc", NL ("const_cast"), 2 }, { "cl", NL ("()"), 2 }, { "cm", NL (","), 2 }, { "co", NL ("~"), 1 }, { "dV", NL ("/="), 2 }, - { "da", NL ("delete[]"), 1 }, + { "da", NL ("delete[] "), 1 }, + { "dc", NL ("dynamic_cast"), 2 }, { "de", NL ("*"), 1 }, - { "dl", NL ("delete"), 1 }, + { "dl", NL ("delete "), 1 }, + { "ds", NL (".*"), 2 }, { "dt", NL ("."), 2 }, { "dv", NL ("/"), 2 }, { "eO", NL ("^="), 2 }, { "eo", NL ("^"), 2 }, { "eq", NL ("=="), 2 }, { "ge", NL (">="), 2 }, + { "gs", NL ("::"), 1 }, { "gt", NL (">"), 2 }, { "ix", NL ("[]"), 2 }, { "lS", NL ("<<="), 2 }, { "le", NL ("<="), 2 }, + { "li", NL ("operator\"\" "), 1 }, { "ls", NL ("<<"), 2 }, { "lt", NL ("<"), 2 }, { "mI", NL ("-="), 2 }, @@ -1557,11 +1729,11 @@ const struct demangle_operator_info cplus_demangle_operators[] = { "mi", NL ("-"), 2 }, { "ml", NL ("*"), 2 }, { "mm", NL ("--"), 1 }, - { "na", NL ("new[]"), 1 }, + { "na", NL ("new[]"), 3 }, { "ne", NL ("!="), 2 }, { "ng", NL ("-"), 1 }, { "nt", NL ("!"), 1 }, - { "nw", NL ("new"), 1 }, + { "nw", NL ("new"), 3 }, { "oR", NL ("|="), 2 }, { "oo", NL ("||"), 2 }, { "or", NL ("|"), 2 }, @@ -1574,12 +1746,14 @@ const struct demangle_operator_info cplus_demangle_operators[] = { "qu", NL ("?"), 3 }, { "rM", NL ("%="), 2 }, { "rS", NL (">>="), 2 }, + { "rc", NL ("reinterpret_cast"), 2 }, { "rm", NL ("%"), 2 }, { "rs", NL (">>"), 2 }, + { "sc", NL ("static_cast"), 2 }, { "st", NL ("sizeof "), 1 }, { "sz", NL ("sizeof "), 1 }, - { "at", NL ("alignof "), 1 }, - { "az", NL ("alignof "), 1 }, + { "tr", NL ("throw"), 0 }, + { "tw", NL ("throw "), 1 }, { NULL, NULL, 0, 0 } }; @@ -1594,8 +1768,20 @@ 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; + struct demangle_component *res; + + di->is_conversion = ! di->is_expression; + type = cplus_demangle_type (di); + if (di->is_conversion) + res = d_make_comp (di, DEMANGLE_COMPONENT_CONVERSION, type, NULL); + else + res = d_make_comp (di, DEMANGLE_COMPONENT_CAST, type, NULL); + di->is_conversion = was_conversion; + return res; + } else { /* LOW is the inclusive lower bound. */ @@ -1737,6 +1923,8 @@ d_java_resource (struct d_info *di) ::= GR <name> ::= GA <encoding> ::= Gr <resource name> + ::= GTt <encoding> + ::= GTn <encoding> */ static struct demangle_component * @@ -1809,6 +1997,14 @@ d_special_name (struct d_info *di) return d_make_comp (di, DEMANGLE_COMPONENT_JAVA_CLASS, cplus_demangle_type (di), NULL); + case 'H': + return d_make_comp (di, DEMANGLE_COMPONENT_TLS_INIT, + d_name (di), NULL); + + case 'W': + return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER, + d_name (di), NULL); + default: return NULL; } @@ -1821,13 +2017,33 @@ d_special_name (struct d_info *di) return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL); case 'R': - return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, d_name (di), - NULL); + { + struct demangle_component *name = d_name (di); + return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, name, + d_number_component (di)); + } case 'A': return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS, d_encoding (di, 0), NULL); + case 'T': + switch (d_next_char (di)) + { + case 'n': + return d_make_comp (di, DEMANGLE_COMPONENT_NONTRANSACTION_CLONE, + d_encoding (di, 0), NULL); + default: + /* ??? The proposal is that other letters (such as 'h') stand + for different variants of transaction cloning, such as + compiling directly for hardware transaction support. But + they still should all be transactional clones of some sort + so go ahead and call them that. */ + case 't': + return d_make_comp (di, DEMANGLE_COMPONENT_TRANSACTION_CLONE, + d_encoding (di, 0), NULL); + } + case 'r': return d_java_resource (di); @@ -1911,6 +2127,12 @@ d_ctor_dtor_name (struct d_info *di) case '3': kind = gnu_v3_complete_object_allocating_ctor; break; + case '4': + kind = gnu_v3_unified_ctor; + break; + case '5': + kind = gnu_v3_object_ctor_group; + break; default: return NULL; } @@ -1933,6 +2155,13 @@ d_ctor_dtor_name (struct d_info *di) case '2': kind = gnu_v3_base_object_dtor; break; + /* digit '3' is not used */ + case '4': + kind = gnu_v3_unified_dtor; + break; + case '5': + kind = gnu_v3_object_dtor_group; + break; default: return NULL; } @@ -2038,8 +2267,28 @@ cplus_demangle_type (struct d_info *di) pret = d_cv_qualifiers (di, &ret, 0); if (pret == NULL) return NULL; - *pret = cplus_demangle_type (di); - if (! *pret || ! d_add_substitution (di, ret)) + if (d_peek_char (di) == 'F') + { + /* cv-qualifiers before a function type apply to 'this', + so avoid adding the unqualified function type to + the substitution list. */ + *pret = d_function_type (di); + } + else + *pret = cplus_demangle_type (di); + if (!*pret) + return NULL; + if ((*pret)->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS + || (*pret)->type == DEMANGLE_COMPONENT_REFERENCE_THIS) + { + /* Move the ref-qualifier outside the cv-qualifiers so that + they are printed in the right order. */ + struct demangle_component *fn = d_left (*pret); + d_left (*pret) = ret; + ret = *pret; + *pret = fn; + } + if (! d_add_substitution (di, ret)) return NULL; return ret; } @@ -2088,13 +2337,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; @@ -2181,12 +2478,19 @@ cplus_demangle_type (struct d_info *di) d_expression (di), NULL); if (ret && d_next_char (di) != 'E') ret = NULL; + can_subst = 1; break; case 'p': /* Pack expansion. */ ret = d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION, cplus_demangle_type (di), NULL); + can_subst = 1; + break; + + case 'a': + /* auto */ + ret = d_make_name (di, "auto", 4); break; case 'f': @@ -2237,6 +2541,7 @@ cplus_demangle_type (struct d_info *di) case 'v': ret = d_vector_type (di); + can_subst = 1; break; case 'n': @@ -2269,8 +2574,10 @@ static struct demangle_component ** d_cv_qualifiers (struct d_info *di, struct demangle_component **pret, int member_fn) { + struct demangle_component **pstart; char peek; + pstart = pret; peek = d_peek_char (di); while (peek == 'r' || peek == 'V' || peek == 'K') { @@ -2307,10 +2614,63 @@ d_cv_qualifiers (struct d_info *di, peek = d_peek_char (di); } + if (!member_fn && peek == 'F') + { + while (pstart != pret) + { + switch ((*pstart)->type) + { + case DEMANGLE_COMPONENT_RESTRICT: + (*pstart)->type = DEMANGLE_COMPONENT_RESTRICT_THIS; + break; + case DEMANGLE_COMPONENT_VOLATILE: + (*pstart)->type = DEMANGLE_COMPONENT_VOLATILE_THIS; + break; + case DEMANGLE_COMPONENT_CONST: + (*pstart)->type = DEMANGLE_COMPONENT_CONST_THIS; + break; + default: + break; + } + pstart = &d_left (*pstart); + } + } + return pret; } -/* <function-type> ::= F [Y] <bare-function-type> E */ +/* <ref-qualifier> ::= R + ::= O */ + +static struct demangle_component * +d_ref_qualifier (struct d_info *di, struct demangle_component *sub) +{ + struct demangle_component *ret = sub; + char peek; + + peek = d_peek_char (di); + if (peek == 'R' || peek == 'O') + { + enum demangle_component_type t; + if (peek == 'R') + { + t = DEMANGLE_COMPONENT_REFERENCE_THIS; + di->expansion += sizeof "&"; + } + else + { + t = DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS; + di->expansion += sizeof "&&"; + } + d_advance (di, 1); + + ret = d_make_comp (di, t, ret, NULL); + } + + return ret; +} + +/* <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E */ static struct demangle_component * d_function_type (struct d_info *di) @@ -2326,6 +2686,8 @@ d_function_type (struct d_info *di) d_advance (di, 1); } ret = d_bare_function_type (di, 1); + ret = d_ref_qualifier (di, ret); + if (! d_check_char (di, 'E')) return NULL; return ret; @@ -2346,7 +2708,11 @@ d_parmlist (struct d_info *di) struct demangle_component *type; char peek = d_peek_char (di); - if (peek == '\0' || peek == 'E') + if (peek == '\0' || peek == 'E' || peek == '.') + break; + if ((peek == 'R' || peek == 'O') + && d_peek_next_char (di) == 'E') + /* Function ref-qualifier, not a ref prefix for a parameter type. */ break; type = cplus_demangle_type (di); if (type == NULL) @@ -2498,41 +2864,32 @@ d_pointer_to_member_type (struct d_info *di) { struct demangle_component *cl; struct demangle_component *mem; - struct demangle_component **pmem; if (! d_check_char (di, 'M')) return NULL; cl = cplus_demangle_type (di); - - /* The ABI specifies that any type can be a substitution source, and - that M is followed by two types, and that when a CV-qualified - type is seen both the base type and the CV-qualified types are - substitution sources. The ABI also specifies that for a pointer - to a CV-qualified member function, the qualifiers are attached to - the second type. Given the grammar, a plain reading of the ABI - suggests that both the CV-qualified member function and the - non-qualified member function are substitution sources. However, - g++ does not work that way. g++ treats only the CV-qualified - member function as a substitution source. FIXME. So to work - with g++, we need to pull off the CV-qualifiers here, in order to - avoid calling add_substitution() in cplus_demangle_type(). But - for a CV-qualified member which is not a function, g++ does - follow the ABI, so we need to handle that case here by calling - d_add_substitution ourselves. */ - - pmem = d_cv_qualifiers (di, &mem, 1); - if (pmem == NULL) - return NULL; - *pmem = cplus_demangle_type (di); - if (*pmem == NULL) + if (cl == NULL) return NULL; - if (pmem != &mem && (*pmem)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE) - { - if (! d_add_substitution (di, mem)) - return NULL; - } + /* The ABI says, "The type of a non-static member function is considered + to be different, for the purposes of substitution, from the type of a + namespace-scope or static member function whose type appears + similar. The types of two non-static member functions are considered + to be different, for the purposes of substitution, if the functions + are members of different classes. In other words, for the purposes of + substitution, the class of which the function is a member is + considered part of the type of function." + + For a pointer to member function, this call to cplus_demangle_type + will end up adding a (possibly qualified) non-member function type to + the substitution table, which is not correct; however, the member + function type will never be used in a substitution, so putting the + wrong type in the substitution table is harmless. */ + + mem = cplus_demangle_type (di); + if (mem == NULL) + return NULL; return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem); } @@ -2590,8 +2947,10 @@ d_template_args (struct d_info *di) constructor or destructor. */ hold_last_name = di->last_name; - if (! d_check_char (di, 'I')) + if (d_peek_char (di) != 'I' + && d_peek_char (di) != 'J') return NULL; + d_advance (di, 1); if (d_peek_char (di) == 'E') { @@ -2650,6 +3009,7 @@ d_template_arg (struct d_info *di) return d_expr_primary (di); case 'I': + case 'J': /* An argument pack. */ return d_template_args (di); @@ -2658,15 +3018,16 @@ d_template_arg (struct d_info *di) } } -/* Subroutine of <expression> ::= cl <expression>+ E */ +/* Parse a sequence of expressions until we hit the terminator + character. */ static struct demangle_component * -d_exprlist (struct d_info *di) +d_exprlist (struct d_info *di, char terminator) { struct demangle_component *list = NULL; struct demangle_component **p = &list; - if (d_peek_char (di) == 'E') + if (d_peek_char (di) == terminator) { d_advance (di, 1); return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL); @@ -2683,7 +3044,7 @@ d_exprlist (struct d_info *di) return NULL; p = &d_right (*p); - if (d_peek_char (di) == 'E') + if (d_peek_char (di) == terminator) { d_advance (di, 1); break; @@ -2693,6 +3054,18 @@ d_exprlist (struct d_info *di) return list; } +/* Returns nonzero iff OP is an operator for a C++ cast: const_cast, + dynamic_cast, static_cast or reinterpret_cast. */ + +static int +op_is_new_cast (struct demangle_component *op) +{ + const char *code = op->u.s_operator.op->code; + return (code[1] == 'c' + && (code[0] == 's' || code[0] == 'd' + || code[0] == 'c' || code[0] == 'r')); +} + /* <expression> ::= <(unary) operator-name> <expression> ::= <(binary) operator-name> <expression> <expression> ::= <(trinary) operator-name> <expression> <expression> <expression> @@ -2704,8 +3077,8 @@ d_exprlist (struct d_info *di) ::= <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; @@ -2733,17 +3106,25 @@ 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') { /* Function parameter used in a late-specified return type. */ int index; d_advance (di, 2); - index = d_compact_number (di); - if (index < 0) - return NULL; - + if (d_peek_char (di) == 'T') + { + /* 'this' parameter. */ + d_advance (di, 1); + index = 0; + } + else + { + index = d_compact_number (di) + 1; + if (index == 0) + return NULL; + } return d_make_function_param (di, index); } else if (IS_DIGIT (peek) @@ -2766,9 +3147,21 @@ d_expression (struct d_info *di) else return name; } + else if ((peek == 'i' || peek == 't') + && d_peek_next_char (di) == 'l') + { + /* Brace-enclosed initializer list, untyped or typed. */ + struct demangle_component *type = NULL; + if (peek == 't') + type = cplus_demangle_type (di); + d_advance (di, 2); + return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST, + type, d_exprlist (di, 'E')); + } else { struct demangle_component *op; + const char *code = NULL; int args; op = d_operator_name (di); @@ -2776,12 +3169,13 @@ d_expression (struct d_info *di) return NULL; if (op->type == DEMANGLE_COMPONENT_OPERATOR) - di->expansion += op->u.s_operator.op->len - 2; - - if (op->type == DEMANGLE_COMPONENT_OPERATOR - && strcmp (op->u.s_operator.op->code, "st") == 0) - return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, - cplus_demangle_type (di)); + { + code = op->u.s_operator.op->code; + di->expansion += op->u.s_operator.op->len - 2; + if (strcmp (code, "st") == 0) + return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, + cplus_demangle_type (di)); + } switch (op->type) { @@ -2800,26 +3194,46 @@ d_expression (struct d_info *di) switch (args) { + case 0: + return d_make_comp (di, DEMANGLE_COMPONENT_NULLARY, op, NULL); + case 1: { struct demangle_component *operand; + int suffix = 0; + + if (code && (code[0] == 'p' || code[0] == 'm') + && code[1] == code[0]) + /* pp_ and mm_ are the prefix variants. */ + suffix = !d_check_char (di, '_'); + if (op->type == DEMANGLE_COMPONENT_CAST && d_check_char (di, '_')) - operand = d_exprlist (di); + operand = d_exprlist (di, 'E'); else - operand = d_expression (di); - return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, - operand); + operand = d_expression_1 (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); } case 2: { struct demangle_component *left; struct demangle_component *right; - const char *code = op->u.s_operator.op->code; - left = d_expression (di); + if (op_is_new_cast (op)) + left = cplus_demangle_type (di); + else + left = d_expression_1 (di); if (!strcmp (code, "cl")) - right = d_exprlist (di); + right = d_exprlist (di, 'E'); else if (!strcmp (code, "dt") || !strcmp (code, "pt")) { right = d_unqualified_name (di); @@ -2828,7 +3242,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, @@ -2839,17 +3253,50 @@ d_expression (struct d_info *di) { struct demangle_component *first; struct demangle_component *second; + struct demangle_component *third; - first = d_expression (di); - second = d_expression (di); + if (!strcmp (code, "qu")) + { + /* ?: expression. */ + first = d_expression_1 (di); + second = d_expression_1 (di); + third = d_expression_1 (di); + } + else if (code[0] == 'n') + { + /* new-expression. */ + if (code[1] != 'w' && code[1] != 'a') + return NULL; + first = d_exprlist (di, '_'); + second = cplus_demangle_type (di); + if (d_peek_char (di) == 'E') + { + d_advance (di, 1); + third = NULL; + } + else if (d_peek_char (di) == 'p' + && d_peek_next_char (di) == 'i') + { + /* Parenthesized initializer. */ + d_advance (di, 2); + third = d_exprlist (di, 'E'); + } + else if (d_peek_char (di) == 'i' + && d_peek_next_char (di) == 'l') + /* initializer-list. */ + third = d_expression_1 (di); + else + return NULL; + } + else + return NULL; return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op, d_make_comp (di, DEMANGLE_COMPONENT_TRINARY_ARG1, first, d_make_comp (di, DEMANGLE_COMPONENT_TRINARY_ARG2, - second, - d_expression (di)))); + second, third))); } default: return NULL; @@ -2857,6 +3304,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 @@ -2922,6 +3381,7 @@ d_expr_primary (struct d_info *di) /* <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>] ::= Z <(function) encoding> E s [<discriminator>] + ::= Z <(function) encoding> E d [<parameter> number>] _ <entity name> */ static struct demangle_component * @@ -3066,6 +3526,33 @@ d_unnamed_type (struct d_info *di) return ret; } +/* <clone-suffix> ::= [ . <clone-type-identifier> ] [ . <nonnegative number> ]* +*/ + +static struct demangle_component * +d_clone_suffix (struct d_info *di, struct demangle_component *encoding) +{ + const char *suffix = d_str (di); + const char *pend = suffix; + struct demangle_component *n; + + if (*pend == '.' && (IS_LOWER (pend[1]) || pend[1] == '_')) + { + pend += 2; + while (IS_LOWER (*pend) || *pend == '_') + ++pend; + } + while (*pend == '.' && IS_DIGIT (pend[1])) + { + pend += 2; + while (IS_DIGIT (*pend)) + ++pend; + } + d_advance (di, pend - suffix); + n = d_make_name (di, suffix, pend - suffix); + return d_make_comp (di, DEMANGLE_COMPONENT_CLONE, encoding, n); +} + /* Add a new substitution. */ static int @@ -3214,6 +3701,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 @@ -3290,23 +3797,168 @@ d_growable_string_callback_adapter (const char *s, size_t l, void *opaque) d_growable_string_append_buffer (dgs, s, l); } +/* Walk the tree, counting the number of templates encountered, and + the number of times a scope might be saved. These counts will be + used to allocate data structures for d_print_comp, so the logic + here must mirror the logic d_print_comp will use. It is not + important that the resulting numbers are exact, so long as they + are larger than the actual numbers encountered. */ + +static void +d_count_templates_scopes (int *num_templates, int *num_scopes, + const struct demangle_component *dc) +{ + if (dc == NULL) + return; + + switch (dc->type) + { + case DEMANGLE_COMPONENT_NAME: + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + case DEMANGLE_COMPONENT_FUNCTION_PARAM: + case DEMANGLE_COMPONENT_SUB_STD: + case DEMANGLE_COMPONENT_BUILTIN_TYPE: + case DEMANGLE_COMPONENT_OPERATOR: + case DEMANGLE_COMPONENT_CHARACTER: + case DEMANGLE_COMPONENT_NUMBER: + case DEMANGLE_COMPONENT_UNNAMED_TYPE: + break; + + case DEMANGLE_COMPONENT_TEMPLATE: + (*num_templates)++; + goto recurse_left_right; + + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + if (d_left (dc)->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM) + (*num_scopes)++; + goto recurse_left_right; + + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_VTABLE: + case DEMANGLE_COMPONENT_VTT: + case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: + case DEMANGLE_COMPONENT_TYPEINFO: + case DEMANGLE_COMPONENT_TYPEINFO_NAME: + case DEMANGLE_COMPONENT_TYPEINFO_FN: + case DEMANGLE_COMPONENT_THUNK: + case DEMANGLE_COMPONENT_VIRTUAL_THUNK: + case DEMANGLE_COMPONENT_COVARIANT_THUNK: + case DEMANGLE_COMPONENT_JAVA_CLASS: + case DEMANGLE_COMPONENT_GUARD: + case DEMANGLE_COMPONENT_TLS_INIT: + case DEMANGLE_COMPONENT_TLS_WRAPPER: + case DEMANGLE_COMPONENT_REFTEMP: + case DEMANGLE_COMPONENT_HIDDEN_ALIAS: + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_REFERENCE_THIS: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + case DEMANGLE_COMPONENT_VENDOR_TYPE: + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + case DEMANGLE_COMPONENT_ARRAY_TYPE: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + case DEMANGLE_COMPONENT_FIXED_TYPE: + case DEMANGLE_COMPONENT_VECTOR_TYPE: + case DEMANGLE_COMPONENT_ARGLIST: + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + case DEMANGLE_COMPONENT_INITIALIZER_LIST: + case DEMANGLE_COMPONENT_CAST: + case DEMANGLE_COMPONENT_CONVERSION: + case DEMANGLE_COMPONENT_NULLARY: + case DEMANGLE_COMPONENT_UNARY: + case DEMANGLE_COMPONENT_BINARY: + case DEMANGLE_COMPONENT_BINARY_ARGS: + case DEMANGLE_COMPONENT_TRINARY: + case DEMANGLE_COMPONENT_TRINARY_ARG1: + case DEMANGLE_COMPONENT_TRINARY_ARG2: + case DEMANGLE_COMPONENT_LITERAL: + case DEMANGLE_COMPONENT_LITERAL_NEG: + case DEMANGLE_COMPONENT_JAVA_RESOURCE: + case DEMANGLE_COMPONENT_COMPOUND_NAME: + case DEMANGLE_COMPONENT_DECLTYPE: + case DEMANGLE_COMPONENT_TRANSACTION_CLONE: + case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE: + case DEMANGLE_COMPONENT_PACK_EXPANSION: + case DEMANGLE_COMPONENT_TAGGED_NAME: + case DEMANGLE_COMPONENT_CLONE: + recurse_left_right: + d_count_templates_scopes (num_templates, num_scopes, + d_left (dc)); + d_count_templates_scopes (num_templates, num_scopes, + d_right (dc)); + break; + + case DEMANGLE_COMPONENT_CTOR: + d_count_templates_scopes (num_templates, num_scopes, + dc->u.s_ctor.name); + break; + + case DEMANGLE_COMPONENT_DTOR: + d_count_templates_scopes (num_templates, num_scopes, + dc->u.s_dtor.name); + break; + + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + d_count_templates_scopes (num_templates, num_scopes, + dc->u.s_extended_operator.name); + break; + + case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: + case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: + d_count_templates_scopes (num_templates, num_scopes, + d_left (dc)); + break; + + case DEMANGLE_COMPONENT_LAMBDA: + case DEMANGLE_COMPONENT_DEFAULT_ARG: + d_count_templates_scopes (num_templates, num_scopes, + dc->u.s_unary_num.sub); + break; + } +} + /* Initialize a print information structure. */ static void -d_print_init (struct d_print_info *dpi, int options, - demangle_callbackref callback, void *opaque) +d_print_init (struct d_print_info *dpi, demangle_callbackref callback, + void *opaque, const struct demangle_component *dc) { - dpi->options = options; dpi->len = 0; dpi->last_char = '\0'; dpi->templates = NULL; dpi->modifiers = NULL; + dpi->pack_index = 0; dpi->flush_count = 0; dpi->callback = callback; dpi->opaque = opaque; dpi->demangle_failure = 0; + + dpi->saved_scopes = NULL; + dpi->next_saved_scope = 0; + dpi->num_saved_scopes = 0; + + dpi->copy_templates = NULL; + dpi->next_copy_template = 0; + dpi->num_copy_templates = 0; + + d_count_templates_scopes (&dpi->num_copy_templates, + &dpi->num_saved_scopes, dc); + dpi->num_copy_templates *= dpi->num_saved_scopes; + + dpi->current_template = NULL; } /* Indicate that an error occurred during printing, and test for error. */ @@ -3392,9 +4044,24 @@ cplus_demangle_print_callback (int options, { struct d_print_info dpi; - d_print_init (&dpi, options, callback, opaque); + d_print_init (&dpi, callback, opaque, dc); + + { +#ifdef CP_DYNAMIC_ARRAYS + __extension__ struct d_saved_scope scopes[dpi.num_saved_scopes]; + __extension__ struct d_print_template temps[dpi.num_copy_templates]; - d_print_comp (&dpi, dc); + dpi.saved_scopes = scopes; + dpi.copy_templates = temps; +#else + dpi.saved_scopes = alloca (dpi.num_saved_scopes + * sizeof (*dpi.saved_scopes)); + dpi.copy_templates = alloca (dpi.num_copy_templates + * sizeof (*dpi.copy_templates)); +#endif + + d_print_comp (&dpi, options, dc); + } d_print_flush (&dpi); @@ -3496,11 +4163,13 @@ d_find_pack (struct d_print_info *dpi, case DEMANGLE_COMPONENT_LAMBDA: case DEMANGLE_COMPONENT_NAME: + case DEMANGLE_COMPONENT_TAGGED_NAME: case DEMANGLE_COMPONENT_OPERATOR: case DEMANGLE_COMPONENT_BUILTIN_TYPE: case DEMANGLE_COMPONENT_SUB_STD: case DEMANGLE_COMPONENT_CHARACTER: case DEMANGLE_COMPONENT_FUNCTION_PARAM: + case DEMANGLE_COMPONENT_UNNAMED_TYPE: return NULL; case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: @@ -3537,26 +4206,95 @@ d_pack_length (const struct demangle_component *dc) if needed. */ static void -d_print_subexpr (struct d_print_info *dpi, +d_print_subexpr (struct d_print_info *dpi, int options, const struct demangle_component *dc) { int simple = 0; if (dc->type == DEMANGLE_COMPONENT_NAME + || dc->type == DEMANGLE_COMPONENT_QUAL_NAME + || dc->type == DEMANGLE_COMPONENT_INITIALIZER_LIST || dc->type == DEMANGLE_COMPONENT_FUNCTION_PARAM) simple = 1; if (!simple) d_append_char (dpi, '('); - d_print_comp (dpi, dc); + d_print_comp (dpi, options, dc); if (!simple) d_append_char (dpi, ')'); } +/* Save the current scope. */ + +static void +d_save_scope (struct d_print_info *dpi, + const struct demangle_component *container) +{ + struct d_saved_scope *scope; + struct d_print_template *src, **link; + + if (dpi->next_saved_scope >= dpi->num_saved_scopes) + { + d_print_error (dpi); + return; + } + scope = &dpi->saved_scopes[dpi->next_saved_scope]; + dpi->next_saved_scope++; + + scope->container = container; + link = &scope->templates; + + for (src = dpi->templates; src != NULL; src = src->next) + { + struct d_print_template *dst; + + if (dpi->next_copy_template >= dpi->num_copy_templates) + { + d_print_error (dpi); + return; + } + dst = &dpi->copy_templates[dpi->next_copy_template]; + dpi->next_copy_template++; + + dst->template_decl = src->template_decl; + *link = dst; + link = &dst->next; + } + + *link = NULL; +} + +/* Attempt to locate a previously saved scope. Returns NULL if no + corresponding saved scope was found. */ + +static struct d_saved_scope * +d_get_saved_scope (struct d_print_info *dpi, + const struct demangle_component *container) +{ + int i; + + for (i = 0; i < dpi->next_saved_scope; i++) + if (dpi->saved_scopes[i].container == container) + return &dpi->saved_scopes[i]; + + return NULL; +} + /* Subroutine to handle components. */ static void -d_print_comp (struct d_print_info *dpi, +d_print_comp (struct d_print_info *dpi, int options, const struct demangle_component *dc) { + /* Magic variable to let reference smashing skip over the next modifier + without needing to modify *dc. */ + const struct demangle_component *mod_inner = NULL; + + /* Variable used to store the current templates while a previously + captured scope is used. */ + struct d_print_template *saved_templates; + + /* Nonzero if templates have been stored in the above variable. */ + int need_template_restore = 0; + if (dc == NULL) { d_print_error (dpi); @@ -3568,20 +4306,37 @@ d_print_comp (struct d_print_info *dpi, switch (dc->type) { case DEMANGLE_COMPONENT_NAME: - if ((dpi->options & DMGL_JAVA) == 0) + if ((options & DMGL_JAVA) == 0) d_append_buffer (dpi, dc->u.s_name.s, dc->u.s_name.len); else d_print_java_identifier (dpi, dc->u.s_name.s, dc->u.s_name.len); return; + case DEMANGLE_COMPONENT_TAGGED_NAME: + d_print_comp (dpi, options, d_left (dc)); + d_append_string (dpi, "[abi:"); + d_print_comp (dpi, options, d_right (dc)); + d_append_char (dpi, ']'); + return; + case DEMANGLE_COMPONENT_QUAL_NAME: case DEMANGLE_COMPONENT_LOCAL_NAME: - d_print_comp (dpi, d_left (dc)); - if ((dpi->options & DMGL_JAVA) == 0) + d_print_comp (dpi, options, d_left (dc)); + if ((options & DMGL_JAVA) == 0) d_append_string (dpi, "::"); else d_append_char (dpi, '.'); - d_print_comp (dpi, d_right (dc)); + { + struct demangle_component *local_name = d_right (dc); + if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG) + { + d_append_string (dpi, "{default arg#"); + d_append_num (dpi, local_name->u.s_unary_num.num + 1); + d_append_string (dpi, "}::"); + local_name = local_name->u.s_unary_num.sub; + } + d_print_comp (dpi, options, local_name); + } return; case DEMANGLE_COMPONENT_TYPED_NAME: @@ -3616,7 +4371,9 @@ d_print_comp (struct d_print_info *dpi, if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS && typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS - && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS) + && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS + && typed_name->type != DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS + && typed_name->type != DEMANGLE_COMPONENT_REFERENCE_THIS) break; typed_name = d_left (typed_name); @@ -3650,7 +4407,10 @@ d_print_comp (struct d_print_info *dpi, local_name = local_name->u.s_unary_num.sub; while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS || local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS - || local_name->type == DEMANGLE_COMPONENT_CONST_THIS) + || local_name->type == DEMANGLE_COMPONENT_CONST_THIS + || local_name->type == DEMANGLE_COMPONENT_REFERENCE_THIS + || (local_name->type + == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)) { if (i >= sizeof adpm / sizeof adpm[0]) { @@ -3671,7 +4431,7 @@ d_print_comp (struct d_print_info *dpi, } } - d_print_comp (dpi, d_right (dc)); + d_print_comp (dpi, options, d_right (dc)); if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE) dpi->templates = dpt.next; @@ -3684,7 +4444,7 @@ d_print_comp (struct d_print_info *dpi, if (! adpm[i].printed) { d_append_char (dpi, ' '); - d_print_mod (dpi, adpm[i].mod); + d_print_mod (dpi, options, adpm[i].mod); } } @@ -3697,6 +4457,12 @@ d_print_comp (struct d_print_info *dpi, { 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. @@ -3707,7 +4473,7 @@ d_print_comp (struct d_print_info *dpi, dcl = d_left (dc); - if ((dpi->options & DMGL_JAVA) != 0 + if ((options & DMGL_JAVA) != 0 && dcl->type == DEMANGLE_COMPONENT_NAME && dcl->u.s_name.len == 6 && strncmp (dcl->u.s_name.s, "JArray", 6) == 0) @@ -3715,16 +4481,16 @@ d_print_comp (struct d_print_info *dpi, /* Special-case Java arrays, so that JArray<TYPE> appears instead as TYPE[]. */ - d_print_comp (dpi, d_right (dc)); + d_print_comp (dpi, options, d_right (dc)); d_append_string (dpi, "[]"); } else { - d_print_comp (dpi, dcl); + d_print_comp (dpi, options, dcl); if (d_last_char (dpi) == '<') d_append_char (dpi, ' '); d_append_char (dpi, '<'); - d_print_comp (dpi, d_right (dc)); + d_print_comp (dpi, options, d_right (dc)); /* Avoid generating two consecutive '>' characters, to avoid the C++ syntactic ambiguity. */ if (d_last_char (dpi) == '>') @@ -3733,6 +4499,7 @@ d_print_comp (struct d_print_info *dpi, } dpi->modifiers = hold_dpm; + dpi->current_template = hold_current; return; } @@ -3759,7 +4526,7 @@ d_print_comp (struct d_print_info *dpi, hold_dpt = dpi->templates; dpi->templates = hold_dpt->next; - d_print_comp (dpi, a); + d_print_comp (dpi, options, a); dpi->templates = hold_dpt; @@ -3767,79 +4534,101 @@ d_print_comp (struct d_print_info *dpi, } case DEMANGLE_COMPONENT_CTOR: - d_print_comp (dpi, dc->u.s_ctor.name); + d_print_comp (dpi, options, dc->u.s_ctor.name); return; case DEMANGLE_COMPONENT_DTOR: d_append_char (dpi, '~'); - d_print_comp (dpi, dc->u.s_dtor.name); + d_print_comp (dpi, options, dc->u.s_dtor.name); return; case DEMANGLE_COMPONENT_VTABLE: d_append_string (dpi, "vtable for "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_VTT: d_append_string (dpi, "VTT for "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: d_append_string (dpi, "construction vtable for "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); d_append_string (dpi, "-in-"); - d_print_comp (dpi, d_right (dc)); + d_print_comp (dpi, options, d_right (dc)); return; case DEMANGLE_COMPONENT_TYPEINFO: d_append_string (dpi, "typeinfo for "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_TYPEINFO_NAME: d_append_string (dpi, "typeinfo name for "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_TYPEINFO_FN: d_append_string (dpi, "typeinfo fn for "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_THUNK: d_append_string (dpi, "non-virtual thunk to "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_VIRTUAL_THUNK: d_append_string (dpi, "virtual thunk to "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_COVARIANT_THUNK: d_append_string (dpi, "covariant return thunk to "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_JAVA_CLASS: d_append_string (dpi, "java Class for "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_GUARD: d_append_string (dpi, "guard variable for "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TLS_INIT: + d_append_string (dpi, "TLS init function for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TLS_WRAPPER: + d_append_string (dpi, "TLS wrapper function for "); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_REFTEMP: - d_append_string (dpi, "reference temporary for "); - d_print_comp (dpi, d_left (dc)); + d_append_string (dpi, "reference temporary #"); + d_print_comp (dpi, options, d_right (dc)); + d_append_string (dpi, " for "); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_HIDDEN_ALIAS: d_append_string (dpi, "hidden alias for "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TRANSACTION_CLONE: + d_append_string (dpi, "transaction clone for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE: + d_append_string (dpi, "non-transaction clone for "); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_SUB_STD: @@ -3866,22 +4655,77 @@ d_print_comp (struct d_print_info *dpi, break; if (pdpm->mod->type == dc->type) { - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); return; } } } } + goto modifier; + + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + { + /* Handle reference smashing: & + && = &. */ + const struct demangle_component *sub = d_left (dc); + if (sub->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM) + { + struct d_saved_scope *scope = d_get_saved_scope (dpi, sub); + struct demangle_component *a; + + if (scope == NULL) + { + /* This is the first time SUB has been traversed. + We need to capture the current templates so + they can be restored if SUB is reentered as a + substitution. */ + d_save_scope (dpi, sub); + if (d_print_saw_error (dpi)) + return; + } + else + { + /* This traversal is reentering SUB as a substition. + Restore the original templates temporarily. */ + saved_templates = dpi->templates; + dpi->templates = scope->templates; + need_template_restore = 1; + } + + a = d_lookup_template_argument (dpi, sub); + if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) + a = d_index_template_argument (a, dpi->pack_index); + + if (a == NULL) + { + if (need_template_restore) + dpi->templates = saved_templates; + + d_print_error (dpi); + return; + } + + sub = a; + } + + if (sub->type == DEMANGLE_COMPONENT_REFERENCE + || sub->type == dc->type) + dc = sub; + else if (sub->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE) + mod_inner = d_left (sub); + } /* Fall through. */ + case DEMANGLE_COMPONENT_RESTRICT_THIS: case DEMANGLE_COMPONENT_VOLATILE_THIS: case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_REFERENCE_THIS: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: case DEMANGLE_COMPONENT_POINTER: - case DEMANGLE_COMPONENT_REFERENCE: - case DEMANGLE_COMPONENT_RVALUE_REFERENCE: case DEMANGLE_COMPONENT_COMPLEX: case DEMANGLE_COMPONENT_IMAGINARY: + modifier: { /* We keep a list of modifiers on the stack. */ struct d_print_mod dpm; @@ -3892,20 +4736,26 @@ d_print_comp (struct d_print_info *dpi, dpm.printed = 0; dpm.templates = dpi->templates; - d_print_comp (dpi, d_left (dc)); + if (!mod_inner) + mod_inner = d_left (dc); + + d_print_comp (dpi, options, mod_inner); /* If the modifier didn't get printed by the type, print it now. */ if (! dpm.printed) - d_print_mod (dpi, dc); + d_print_mod (dpi, options, dc); dpi->modifiers = dpm.next; + if (need_template_restore) + dpi->templates = saved_templates; + return; } case DEMANGLE_COMPONENT_BUILTIN_TYPE: - if ((dpi->options & DMGL_JAVA) == 0) + if ((options & DMGL_JAVA) == 0) d_append_buffer (dpi, dc->u.s_builtin.type->name, dc->u.s_builtin.type->len); else @@ -3914,16 +4764,21 @@ d_print_comp (struct d_print_info *dpi, return; case DEMANGLE_COMPONENT_VENDOR_TYPE: - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_FUNCTION_TYPE: { - if ((dpi->options & DMGL_RET_POSTFIX) != 0) - d_print_function_type (dpi, dc, dpi->modifiers); + if ((options & DMGL_RET_POSTFIX) != 0) + d_print_function_type (dpi, + options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), + dc, dpi->modifiers); /* Print return type if present */ - if (d_left (dc) != NULL) + if (d_left (dc) != NULL && (options & DMGL_RET_POSTFIX) != 0) + d_print_comp (dpi, options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), + d_left (dc)); + else if (d_left (dc) != NULL && (options & DMGL_RET_DROP) == 0) { struct d_print_mod dpm; @@ -3935,7 +4790,8 @@ d_print_comp (struct d_print_info *dpi, dpm.printed = 0; dpm.templates = dpi->templates; - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), + d_left (dc)); dpi->modifiers = dpm.next; @@ -3944,12 +4800,14 @@ d_print_comp (struct d_print_info *dpi, /* In standard prefix notation, there is a space between the return type and the function signature. */ - if ((dpi->options & DMGL_RET_POSTFIX) == 0) + if ((options & DMGL_RET_POSTFIX) == 0) d_append_char (dpi, ' '); } - if ((dpi->options & DMGL_RET_POSTFIX) == 0) - d_print_function_type (dpi, dc, dpi->modifiers); + if ((options & DMGL_RET_POSTFIX) == 0) + d_print_function_type (dpi, + options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), + dc, dpi->modifiers); return; } @@ -4002,7 +4860,7 @@ d_print_comp (struct d_print_info *dpi, pdpm = pdpm->next; } - d_print_comp (dpi, d_right (dc)); + d_print_comp (dpi, options, d_right (dc)); dpi->modifiers = hold_modifiers; @@ -4012,10 +4870,10 @@ d_print_comp (struct d_print_info *dpi, while (i > 1) { --i; - d_print_mod (dpi, adpm[i].mod); + d_print_mod (dpi, options, adpm[i].mod); } - d_print_array_type (dpi, dc, dpi->modifiers); + d_print_array_type (dpi, options, dc, dpi->modifiers); return; } @@ -4031,12 +4889,12 @@ d_print_comp (struct d_print_info *dpi, dpm.printed = 0; dpm.templates = dpi->templates; - d_print_comp (dpi, d_right (dc)); + d_print_comp (dpi, options, d_right (dc)); /* If the modifier didn't get printed by the type, print it now. */ if (! dpm.printed) - d_print_mod (dpi, dc); + d_print_mod (dpi, options, dc); dpi->modifiers = dpm.next; @@ -4050,7 +4908,7 @@ d_print_comp (struct d_print_info *dpi, if (dc->u.s_fixed.length->u.s_builtin.type != &cplus_demangle_builtin_types['i'-'a']) { - d_print_comp (dpi, dc->u.s_fixed.length); + d_print_comp (dpi, options, dc->u.s_fixed.length); d_append_char (dpi, ' '); } if (dc->u.s_fixed.accum) @@ -4062,7 +4920,7 @@ d_print_comp (struct d_print_info *dpi, case DEMANGLE_COMPONENT_ARGLIST: case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: if (d_left (dc) != NULL) - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); if (d_right (dc) != NULL) { size_t len; @@ -4074,7 +4932,7 @@ d_print_comp (struct d_print_info *dpi, d_append_string (dpi, ", "); len = dpi->len; flush_count = dpi->flush_count; - d_print_comp (dpi, d_right (dc)); + d_print_comp (dpi, options, d_right (dc)); /* If that didn't print anything (which can happen with empty template argument packs), remove the comma and space. */ if (dpi->flush_count == flush_count && dpi->len == len) @@ -4082,39 +4940,98 @@ d_print_comp (struct d_print_info *dpi, } return; + case DEMANGLE_COMPONENT_INITIALIZER_LIST: + { + struct demangle_component *type = d_left (dc); + struct demangle_component *list = d_right (dc); + + if (type) + d_print_comp (dpi, options, type); + d_append_char (dpi, '{'); + d_print_comp (dpi, options, list); + d_append_char (dpi, '}'); + } + return; + case DEMANGLE_COMPONENT_OPERATOR: { - char c; + const struct demangle_operator_info *op = dc->u.s_operator.op; + int len = op->len; d_append_string (dpi, "operator"); - c = dc->u.s_operator.op->name[0]; - if (IS_LOWER (c)) + /* Add a space before new/delete. */ + if (IS_LOWER (op->name[0])) d_append_char (dpi, ' '); - d_append_buffer (dpi, dc->u.s_operator.op->name, - dc->u.s_operator.op->len); + /* Omit a trailing space. */ + if (op->name[len-1] == ' ') + --len; + d_append_buffer (dpi, op->name, len); return; } case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: d_append_string (dpi, "operator "); - d_print_comp (dpi, dc->u.s_extended_operator.name); + d_print_comp (dpi, options, dc->u.s_extended_operator.name); return; - case DEMANGLE_COMPONENT_CAST: + case DEMANGLE_COMPONENT_CONVERSION: d_append_string (dpi, "operator "); - d_print_cast (dpi, dc); + d_print_conversion (dpi, options, dc); + return; + + case DEMANGLE_COMPONENT_NULLARY: + d_print_expr_op (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_UNARY: - if (d_left (dc)->type != DEMANGLE_COMPONENT_CAST) - d_print_expr_op (dpi, d_left (dc)); - else - { - d_append_char (dpi, '('); - d_print_cast (dpi, d_left (dc)); - d_append_char (dpi, ')'); - } - d_print_subexpr (dpi, d_right (dc)); + { + struct demangle_component *op = d_left (dc); + struct demangle_component *operand = d_right (dc); + const char *code = NULL; + + if (op->type == DEMANGLE_COMPONENT_OPERATOR) + { + code = op->u.s_operator.op->code; + if (!strcmp (code, "ad")) + { + /* Don't print the argument list for the address of a + function. */ + if (operand->type == DEMANGLE_COMPONENT_TYPED_NAME + && d_left (operand)->type == DEMANGLE_COMPONENT_QUAL_NAME + && d_right (operand)->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) + operand = d_left (operand); + } + if (operand->type == DEMANGLE_COMPONENT_BINARY_ARGS) + { + /* This indicates a suffix operator. */ + operand = d_left (operand); + d_print_subexpr (dpi, options, operand); + d_print_expr_op (dpi, options, op); + return; + } + } + + if (op->type != DEMANGLE_COMPONENT_CAST) + d_print_expr_op (dpi, options, op); + else + { + d_append_char (dpi, '('); + d_print_cast (dpi, options, op); + d_append_char (dpi, ')'); + } + if (code && !strcmp (code, "gs")) + /* Avoid parens after '::'. */ + d_print_comp (dpi, options, operand); + else if (code && !strcmp (code, "st")) + /* Always print parens for sizeof (type). */ + { + d_append_char (dpi, '('); + d_print_comp (dpi, options, operand); + d_append_char (dpi, ')'); + } + else + d_print_subexpr (dpi, options, operand); + } return; case DEMANGLE_COMPONENT_BINARY: @@ -4124,6 +5041,17 @@ d_print_comp (struct d_print_info *dpi, return; } + if (op_is_new_cast (d_left (dc))) + { + d_print_expr_op (dpi, options, d_left (dc)); + d_append_char (dpi, '<'); + d_print_comp (dpi, options, d_left (d_right (dc))); + d_append_string (dpi, ">("); + d_print_comp (dpi, options, d_right (d_right (dc))); + d_append_char (dpi, ')'); + return; + } + /* We wrap an expression which uses the greater-than operator in an extra layer of parens so that it does not get confused with the '>' which ends the template parameters. */ @@ -4132,18 +5060,32 @@ d_print_comp (struct d_print_info *dpi, && d_left (dc)->u.s_operator.op->name[0] == '>') d_append_char (dpi, '('); - d_print_subexpr (dpi, d_left (d_right (dc))); + if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") == 0 + && d_left (d_right (dc))->type == DEMANGLE_COMPONENT_TYPED_NAME) + { + /* Function call used in an expression should not have printed types + of the function arguments. Values of the function arguments still + get printed below. */ + + const struct demangle_component *func = d_left (d_right (dc)); + + if (d_right (func)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE) + d_print_error (dpi); + d_print_subexpr (dpi, options, d_left (func)); + } + else + d_print_subexpr (dpi, options, d_left (d_right (dc))); if (strcmp (d_left (dc)->u.s_operator.op->code, "ix") == 0) { d_append_char (dpi, '['); - d_print_comp (dpi, d_right (d_right (dc))); + d_print_comp (dpi, options, d_right (d_right (dc))); d_append_char (dpi, ']'); } else { if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") != 0) - d_print_expr_op (dpi, d_left (dc)); - d_print_subexpr (dpi, d_right (d_right (dc))); + d_print_expr_op (dpi, options, d_left (dc)); + d_print_subexpr (dpi, options, d_right (d_right (dc))); } if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR @@ -4165,11 +5107,33 @@ d_print_comp (struct d_print_info *dpi, d_print_error (dpi); return; } - d_print_subexpr (dpi, d_left (d_right (dc))); - d_print_expr_op (dpi, d_left (dc)); - d_print_subexpr (dpi, d_left (d_right (d_right (dc)))); - d_append_string (dpi, " : "); - d_print_subexpr (dpi, d_right (d_right (d_right (dc)))); + { + struct demangle_component *op = d_left (dc); + struct demangle_component *first = d_left (d_right (dc)); + struct demangle_component *second = d_left (d_right (d_right (dc))); + struct demangle_component *third = d_right (d_right (d_right (dc))); + + if (!strcmp (op->u.s_operator.op->code, "qu")) + { + d_print_subexpr (dpi, options, first); + d_print_expr_op (dpi, options, op); + d_print_subexpr (dpi, options, second); + d_append_string (dpi, " : "); + d_print_subexpr (dpi, options, third); + } + else + { + d_append_string (dpi, "new "); + if (d_left (first) != NULL) + { + d_print_subexpr (dpi, options, first); + d_append_char (dpi, ' '); + } + d_print_comp (dpi, options, second); + if (third) + d_print_subexpr (dpi, options, third); + } + } return; case DEMANGLE_COMPONENT_TRINARY_ARG1: @@ -4200,7 +5164,7 @@ d_print_comp (struct d_print_info *dpi, { if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG) d_append_char (dpi, '-'); - d_print_comp (dpi, d_right (dc)); + d_print_comp (dpi, options, d_right (dc)); switch (tp) { default: @@ -4250,13 +5214,13 @@ d_print_comp (struct d_print_info *dpi, } d_append_char (dpi, '('); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); d_append_char (dpi, ')'); if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG) d_append_char (dpi, '-'); if (tp == D_PRINT_FLOAT) d_append_char (dpi, '['); - d_print_comp (dpi, d_right (dc)); + d_print_comp (dpi, options, d_right (dc)); if (tp == D_PRINT_FLOAT) d_append_char (dpi, ']'); } @@ -4268,12 +5232,12 @@ d_print_comp (struct d_print_info *dpi, case DEMANGLE_COMPONENT_JAVA_RESOURCE: d_append_string (dpi, "java resource "); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); return; case DEMANGLE_COMPONENT_COMPOUND_NAME: - d_print_comp (dpi, d_left (dc)); - d_print_comp (dpi, d_right (dc)); + d_print_comp (dpi, options, d_left (dc)); + d_print_comp (dpi, options, d_right (dc)); return; case DEMANGLE_COMPONENT_CHARACTER: @@ -4282,7 +5246,7 @@ d_print_comp (struct d_print_info *dpi, case DEMANGLE_COMPONENT_DECLTYPE: d_append_string (dpi, "decltype ("); - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); d_append_char (dpi, ')'); return; @@ -4296,7 +5260,7 @@ d_print_comp (struct d_print_info *dpi, /* d_find_pack won't find anything if the only packs involved in this expansion are function parameter packs; in that case, just print the pattern and "...". */ - d_print_subexpr (dpi, d_left (dc)); + d_print_subexpr (dpi, options, d_left (dc)); d_append_string (dpi, "..."); return; } @@ -4306,7 +5270,7 @@ d_print_comp (struct d_print_info *dpi, for (i = 0; i < len; ++i) { dpi->pack_index = i; - d_print_comp (dpi, dc); + d_print_comp (dpi, options, dc); if (i < len-1) d_append_string (dpi, ", "); } @@ -4314,24 +5278,32 @@ d_print_comp (struct d_print_info *dpi, return; case DEMANGLE_COMPONENT_FUNCTION_PARAM: - d_append_string (dpi, "{parm#"); - d_append_num (dpi, dc->u.s_number.number + 1); - d_append_char (dpi, '}'); + { + long num = dc->u.s_number.number; + if (num == 0) + d_append_string (dpi, "this"); + else + { + d_append_string (dpi, "{parm#"); + d_append_num (dpi, num); + d_append_char (dpi, '}'); + } + } return; case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: d_append_string (dpi, "global constructors keyed to "); - d_print_comp (dpi, dc->u.s_binary.left); + d_print_comp (dpi, options, dc->u.s_binary.left); return; case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: d_append_string (dpi, "global destructors keyed to "); - d_print_comp (dpi, dc->u.s_binary.left); + d_print_comp (dpi, options, dc->u.s_binary.left); return; case DEMANGLE_COMPONENT_LAMBDA: d_append_string (dpi, "{lambda("); - d_print_comp (dpi, dc->u.s_unary_num.sub); + d_print_comp (dpi, options, dc->u.s_unary_num.sub); d_append_string (dpi, ")#"); d_append_num (dpi, dc->u.s_unary_num.num + 1); d_append_char (dpi, '}'); @@ -4343,6 +5315,13 @@ d_print_comp (struct d_print_info *dpi, d_append_char (dpi, '}'); return; + case DEMANGLE_COMPONENT_CLONE: + d_print_comp (dpi, options, d_left (dc)); + d_append_string (dpi, " [clone "); + d_print_comp (dpi, options, d_right (dc)); + d_append_char (dpi, ']'); + return; + default: d_print_error (dpi); return; @@ -4405,7 +5384,7 @@ d_print_java_identifier (struct d_print_info *dpi, const char *name, int len) qualifiers on this after printing a function. */ static void -d_print_mod_list (struct d_print_info *dpi, +d_print_mod_list (struct d_print_info *dpi, int options, struct d_print_mod *mods, int suffix) { struct d_print_template *hold_dpt; @@ -4417,9 +5396,12 @@ d_print_mod_list (struct d_print_info *dpi, || (! suffix && (mods->mod->type == DEMANGLE_COMPONENT_RESTRICT_THIS || mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS - || mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS))) + || mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS + || mods->mod->type == DEMANGLE_COMPONENT_REFERENCE_THIS + || (mods->mod->type + == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)))) { - d_print_mod_list (dpi, mods->next, suffix); + d_print_mod_list (dpi, options, mods->next, suffix); return; } @@ -4430,13 +5412,13 @@ d_print_mod_list (struct d_print_info *dpi, if (mods->mod->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) { - d_print_function_type (dpi, mods->mod, mods->next); + d_print_function_type (dpi, options, mods->mod, mods->next); dpi->templates = hold_dpt; return; } else if (mods->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE) { - d_print_array_type (dpi, mods->mod, mods->next); + d_print_array_type (dpi, options, mods->mod, mods->next); dpi->templates = hold_dpt; return; } @@ -4452,10 +5434,10 @@ d_print_mod_list (struct d_print_info *dpi, hold_modifiers = dpi->modifiers; dpi->modifiers = NULL; - d_print_comp (dpi, d_left (mods->mod)); + d_print_comp (dpi, options, d_left (mods->mod)); dpi->modifiers = hold_modifiers; - if ((dpi->options & DMGL_JAVA) == 0) + if ((options & DMGL_JAVA) == 0) d_append_string (dpi, "::"); else d_append_char (dpi, '.'); @@ -4472,26 +5454,28 @@ d_print_mod_list (struct d_print_info *dpi, while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS - || dc->type == DEMANGLE_COMPONENT_CONST_THIS) + || dc->type == DEMANGLE_COMPONENT_CONST_THIS + || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS + || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS) dc = d_left (dc); - d_print_comp (dpi, dc); + d_print_comp (dpi, options, dc); dpi->templates = hold_dpt; return; } - d_print_mod (dpi, mods->mod); + d_print_mod (dpi, options, mods->mod); dpi->templates = hold_dpt; - d_print_mod_list (dpi, mods->next, suffix); + d_print_mod_list (dpi, options, mods->next, suffix); } /* Print a modifier. */ static void -d_print_mod (struct d_print_info *dpi, +d_print_mod (struct d_print_info *dpi, int options, const struct demangle_component *mod) { switch (mod->type) @@ -4510,16 +5494,21 @@ d_print_mod (struct d_print_info *dpi, return; case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: d_append_char (dpi, ' '); - d_print_comp (dpi, d_right (mod)); + d_print_comp (dpi, options, d_right (mod)); return; case DEMANGLE_COMPONENT_POINTER: /* There is no pointer symbol in Java. */ - if ((dpi->options & DMGL_JAVA) == 0) + if ((options & DMGL_JAVA) == 0) d_append_char (dpi, '*'); return; + case DEMANGLE_COMPONENT_REFERENCE_THIS: + /* For the ref-qualifier, put a space before the &. */ + d_append_char (dpi, ' '); case DEMANGLE_COMPONENT_REFERENCE: d_append_char (dpi, '&'); return; + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: + d_append_char (dpi, ' '); case DEMANGLE_COMPONENT_RVALUE_REFERENCE: d_append_string (dpi, "&&"); return; @@ -4532,22 +5521,22 @@ d_print_mod (struct d_print_info *dpi, case DEMANGLE_COMPONENT_PTRMEM_TYPE: if (d_last_char (dpi) != '(') d_append_char (dpi, ' '); - d_print_comp (dpi, d_left (mod)); + d_print_comp (dpi, options, d_left (mod)); d_append_string (dpi, "::*"); return; case DEMANGLE_COMPONENT_TYPED_NAME: - d_print_comp (dpi, d_left (mod)); + d_print_comp (dpi, options, d_left (mod)); return; case DEMANGLE_COMPONENT_VECTOR_TYPE: d_append_string (dpi, " __vector("); - d_print_comp (dpi, d_left (mod)); + d_print_comp (dpi, options, d_left (mod)); d_append_char (dpi, ')'); return; default: /* Otherwise, we have something that won't go back on the modifier stack, so we can just print it. */ - d_print_comp (dpi, mod); + d_print_comp (dpi, options, mod); return; } } @@ -4555,7 +5544,7 @@ d_print_mod (struct d_print_info *dpi, /* Print a function type, except for the return type. */ static void -d_print_function_type (struct d_print_info *dpi, +d_print_function_type (struct d_print_info *dpi, int options, const struct demangle_component *dc, struct d_print_mod *mods) { @@ -4591,6 +5580,8 @@ d_print_function_type (struct d_print_info *dpi, case DEMANGLE_COMPONENT_RESTRICT_THIS: case DEMANGLE_COMPONENT_VOLATILE_THIS: case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_REFERENCE_THIS: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: break; default: break; @@ -4615,7 +5606,7 @@ d_print_function_type (struct d_print_info *dpi, hold_modifiers = dpi->modifiers; dpi->modifiers = NULL; - d_print_mod_list (dpi, mods, 0); + d_print_mod_list (dpi, options, mods, 0); if (need_paren) d_append_char (dpi, ')'); @@ -4623,11 +5614,11 @@ d_print_function_type (struct d_print_info *dpi, d_append_char (dpi, '('); if (d_right (dc) != NULL) - d_print_comp (dpi, d_right (dc)); + d_print_comp (dpi, options, d_right (dc)); d_append_char (dpi, ')'); - d_print_mod_list (dpi, mods, 1); + d_print_mod_list (dpi, options, mods, 1); dpi->modifiers = hold_modifiers; } @@ -4635,7 +5626,7 @@ d_print_function_type (struct d_print_info *dpi, /* Print an array type, except for the element type. */ static void -d_print_array_type (struct d_print_info *dpi, +d_print_array_type (struct d_print_info *dpi, int options, const struct demangle_component *dc, struct d_print_mod *mods) { @@ -4669,7 +5660,7 @@ d_print_array_type (struct d_print_info *dpi, if (need_paren) d_append_string (dpi, " ("); - d_print_mod_list (dpi, mods, 0); + d_print_mod_list (dpi, options, mods, 0); if (need_paren) d_append_char (dpi, ')'); @@ -4681,7 +5672,7 @@ d_print_array_type (struct d_print_info *dpi, d_append_char (dpi, '['); if (d_left (dc) != NULL) - d_print_comp (dpi, d_left (dc)); + d_print_comp (dpi, options, d_left (dc)); d_append_char (dpi, ']'); } @@ -4689,56 +5680,67 @@ d_print_array_type (struct d_print_info *dpi, /* Print an operator in an expression. */ static void -d_print_expr_op (struct d_print_info *dpi, +d_print_expr_op (struct d_print_info *dpi, int options, const struct demangle_component *dc) { if (dc->type == DEMANGLE_COMPONENT_OPERATOR) d_append_buffer (dpi, dc->u.s_operator.op->name, dc->u.s_operator.op->len); else - d_print_comp (dpi, dc); + d_print_comp (dpi, options, dc); } /* Print a cast. */ static void -d_print_cast (struct d_print_info *dpi, - const struct demangle_component *dc) +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, d_left (dc)); - else - { - struct d_print_mod *hold_dpm; - struct d_print_template dpt; + d_print_comp (dpi, options, d_left (dc)); +} - /* 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. */ +/* Print a conversion operator. */ - hold_dpm = dpi->modifiers; - dpi->modifiers = NULL; +static void +d_print_conversion (struct d_print_info *dpi, int options, + const struct demangle_component *dc) +{ + struct d_print_template dpt; + /* For a conversion 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; + } - d_print_comp (dpi, d_left (d_left (dc))); + 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, ' '); d_append_char (dpi, '<'); - d_print_comp (dpi, d_right (d_left (dc))); + d_print_comp (dpi, options, d_right (d_left (dc))); /* Avoid generating two consecutive '>' characters, to avoid the C++ syntactic ambiguity. */ if (d_last_char (dpi) == '>') d_append_char (dpi, ' '); d_append_char (dpi, '>'); - - dpi->modifiers = hold_dpm; } } @@ -4771,6 +5773,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 @@ -4841,6 +5845,8 @@ d_demangle_callback (const char *mangled, int options, NULL); d_advance (&di, strlen (d_str (&di))); break; + default: + abort (); /* We have listed all the cases. */ } /* If DMGL_PARAMS is set, then if we didn't consume the entire @@ -5111,14 +6117,17 @@ is_ctor_or_dtor (const char *mangled, { switch (dc->type) { + /* These cannot appear on a constructor or destructor. */ + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_REFERENCE_THIS: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: default: dc = NULL; break; case DEMANGLE_COMPONENT_TYPED_NAME: case DEMANGLE_COMPONENT_TEMPLATE: - case DEMANGLE_COMPONENT_RESTRICT_THIS: - case DEMANGLE_COMPONENT_VOLATILE_THIS: - case DEMANGLE_COMPONENT_CONST_THIS: dc = d_left (dc); break; case DEMANGLE_COMPONENT_QUAL_NAME: diff --git a/cp-demangle.h b/cp-demangle.h index ae635be..6fce025 100644 --- a/cp-demangle.h +++ b/cp-demangle.h @@ -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: @@ -45,7 +45,13 @@ extern "C" { #define DMGL_VERBOSE (1 << 3) /* Include implementation details. */ #define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */ #define DMGL_RET_POSTFIX (1 << 5) /* Print function return types (when - present) after function signature */ + present) after function signature. + It applies only to the toplevel + function type. */ +#define DMGL_RET_DROP (1 << 6) /* Suppress printing function return + types, even if present. It applies + only to the toplevel function type. + */ #define DMGL_AUTO (1 << 8) #define DMGL_GNU (1 << 9) @@ -166,7 +172,12 @@ ada_demangle (const char *mangled, int options); enum gnu_v3_ctor_kinds { gnu_v3_complete_object_ctor = 1, gnu_v3_base_object_ctor, - gnu_v3_complete_object_allocating_ctor + gnu_v3_complete_object_allocating_ctor, + /* These are not part of the V3 ABI. Unified constructors are generated + as a speed-for-space optimization when the -fdeclone-ctor-dtor option + is used, and are always internal symbols. */ + gnu_v3_unified_ctor, + gnu_v3_object_ctor_group }; /* Return non-zero iff NAME is the mangled form of a constructor name @@ -180,7 +191,12 @@ extern enum gnu_v3_ctor_kinds enum gnu_v3_dtor_kinds { gnu_v3_deleting_dtor = 1, gnu_v3_complete_object_dtor, - gnu_v3_base_object_dtor + gnu_v3_base_object_dtor, + /* These are not part of the V3 ABI. Unified destructors are generated + as a speed-for-space optimization when the -fdeclone-ctor-dtor option + is used, and are always internal symbols. */ + gnu_v3_unified_dtor, + gnu_v3_object_dtor_group }; /* Return non-zero iff NAME is the mangled form of a destructor name @@ -264,6 +280,9 @@ enum demangle_component_type /* A guard variable. This has one subtree, the name for which this is a guard variable. */ DEMANGLE_COMPONENT_GUARD, + /* The init and wrapper functions for C++11 thread_local variables. */ + DEMANGLE_COMPONENT_TLS_INIT, + DEMANGLE_COMPONENT_TLS_WRAPPER, /* A reference temporary. This has one subtree, the name for which this is a temporary. */ DEMANGLE_COMPONENT_REFTEMP, @@ -291,6 +310,12 @@ enum demangle_component_type /* The const qualifier modifying a member function. The one subtree is the type which is being qualified. */ DEMANGLE_COMPONENT_CONST_THIS, + /* C++11 A reference modifying a member function. The one subtree is the + type which is being referenced. */ + DEMANGLE_COMPONENT_REFERENCE_THIS, + /* C++11: An rvalue reference modifying a member function. The one + subtree is the type which is being referenced. */ + DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS, /* A vendor qualifier. The left subtree is the type which is being qualified, and the right subtree is the name of the qualifier. */ @@ -336,6 +361,9 @@ enum demangle_component_type template argument, and the right subtree is either NULL or another TEMPLATE_ARGLIST node. */ DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, + /* An initializer list. The left subtree is either an explicit type or + NULL, and the right subtree is a DEMANGLE_COMPONENT_ARGLIST. */ + DEMANGLE_COMPONENT_INITIALIZER_LIST, /* An operator. This holds information about a standard operator. */ DEMANGLE_COMPONENT_OPERATOR, @@ -345,6 +373,12 @@ enum demangle_component_type /* A typecast, represented as a unary operator. The one subtree is the type to which the argument should be cast. */ DEMANGLE_COMPONENT_CAST, + /* A conversion operator, represented as a unary operator. The one + subtree is the type to which the argument should be converted + to. */ + DEMANGLE_COMPONENT_CONVERSION, + /* A nullary expression. The left subtree is the operator. */ + DEMANGLE_COMPONENT_NULLARY, /* A unary expression. The left subtree is the operator, and the right subtree is the single argument. */ DEMANGLE_COMPONENT_UNARY, @@ -395,8 +429,19 @@ enum demangle_component_type DEMANGLE_COMPONENT_DEFAULT_ARG, /* An unnamed type. */ DEMANGLE_COMPONENT_UNNAMED_TYPE, + /* A transactional clone. This has one subtree, the encoding for + which it is providing alternative linkage. */ + DEMANGLE_COMPONENT_TRANSACTION_CLONE, + /* A non-transactional clone entry point. In the i386/x86_64 abi, + the unmangled symbol of a tm_callable becomes a thunk and the + non-transactional function version is mangled thus. */ + DEMANGLE_COMPONENT_NONTRANSACTION_CLONE, /* A pack expansion. */ - DEMANGLE_COMPONENT_PACK_EXPANSION + DEMANGLE_COMPONENT_PACK_EXPANSION, + /* A name with an ABI tag. */ + DEMANGLE_COMPONENT_TAGGED_NAME, + /* A cloned function. */ + DEMANGLE_COMPONENT_CLONE }; /* Types which are only used internally. */ diff --git a/demangle_test.cpp b/demangle_test.cpp new file mode 100644 index 0000000..324ac19 --- /dev/null +++ b/demangle_test.cpp @@ -0,0 +1,74 @@ +#include <gtest/gtest.h> + +#include <stdio.h> +#include <stdlib.h> + +extern "C" { + +extern char *__cxa_demangle (const char *mangled, char *buf, size_t *len, + int *status); + +} + +const char* names[] = { + "_Z3fo5n", + "_Z3fo5o", + "_ZN1f1fE", + "_Z1fv", + "_Z1fi", + "_Z3foo3bar", + "_Zrm1XS_", + "_ZplR1XS0_", + "_ZlsRK1XS1_", + "_ZN3FooIA4_iE3barE", + "_Z1fIiEvi", + "_Z5firstI3DuoEvS0_", + "_Z5firstI3DuoEvT_", + "_Z3fooIiFvdEiEvv", + "_Z1fIFvvEEvv", + "_ZN1N1fE", + "_ZN6System5Sound4beepEv", + "_ZN6SkPath4IterC1ERKS_b", + "_ZN6SkPath4Iter4nextEP7SkPoint", + "_ZN6SkScan8HairLineERK7SkPointS2_PK8SkRegionP9SkBlitter", + "_Z3fooiPiPS_PS0_PS1_PS2_PS3_PS4_PS5_PS6_PS7_PS8_PS9_PSA_PSB_PSC_", + "_Z1fILi1ELc120EEv1AIXplT_cviLd810000000000000000703DAD7A370C5EEE", + "_ZZN7myspaceL3foo_1EvEN11localstruct1fEZNS_3fooEvE16otherlocalstruct", + "_Z7ZipWithI7QStringS0_5QListZN4oral6detail16AdaptCreateTableI7AccountEES0_RKNS3_16CachedFieldsDataEEUlRKS0_SA_E_ET1_IDTclfp1_cvT__EcvT0__EEEERKT1_ISC_ERKT1_ISD_ET2_", + NULL}; + +const char* expected[] = { + "fo5(__int128)", + "fo5(unsigned __int128)", + "f::f", + "f()", + "f(int)", + "foo(bar)", + "operator%(X, X)", + "operator+(X&, X&)", + "operator<<(X const&, X const&)", + "Foo<int [4]>::bar", + "void f<int>(int)", + "void first<Duo>(Duo)", + "void first<Duo>(Duo)", + "void foo<int, void (double), int>()", + "void f<void ()>()", + "N::f", + "System::Sound::beep()", + "SkPath::Iter::Iter(SkPath const&, bool)", + "SkPath::Iter::next(SkPoint*)", + "SkScan::HairLine(SkPoint const&, SkPoint const&, SkRegion const*, SkBlitter*)", + "foo(int, int*, int**, int***, int****, int*****, int******, int*******, int********, int*********, int**********, int***********, int************, int*************, int**************, int***************)", + "void f<1, (char)120>(A<(1)+((int)((double)[810000000000000000703DAD7A370C5]))>)", + "myspace::foo()::localstruct::f(myspace::foo()::otherlocalstruct)", + "QList<decltype ({parm#3}((QString)(), (QString)()))> ZipWith<QString, QString, QList, QString oral::detail::AdaptCreateTable<Account>(oral::detail::CachedFieldsData const&)::{lambda(QString const&, QString const&)#1}>(QList<QString oral::detail::AdaptCreateTable<Account>(oral::detail::CachedFieldsData const&)::{lambda(QString const&, QString const&)#1}> const&, QList<QList> const&, QString oral::detail::AdaptCreateTable<Account>(oral::detail::CachedFieldsData const&)::{lambda(QString const&, QString const&)#1})", + "" +}; + +TEST(gcc_demangle, smoke) { + for (int i = 0; names[i] != NULL; ++i) { + char *demangled = __cxa_demangle(names[i], 0, 0, 0); + ASSERT_STREQ(expected[i], demangled); + free(demangled); + } +} @@ -1,21 +0,0 @@ -#include <stdio.h> - -const char* names[4] = {"_ZN6SkPath4IterC1ERKS_b", - "_ZN6SkPath4Iter4nextEP7SkPoint", - "_ZN6SkScan8HairLineERK7SkPointS2_PK8SkRegionP9SkBlitter", - NULL}; - -extern char *__cxa_demangle (const char *mangled, char *buf, size_t *len, - int *status); - -char* demangle_symbol_name(const char*name) { - return name ? __cxa_demangle(name, 0, 0, 0) : ""; -} - -int main() { - int i; - for (i=0; i<4; ++i) { - printf ("%s -> %s\n", names[i], demangle_symbol_name(names[i])); - } - return 0; -} |