Index: libiberty/cp-demangle.c |
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c |
index 27cc323f2a24c03c584e8ec74961d9d92e5e49b0..029151e320aadddd23642470434b5aa90761f9e1 100644 |
--- a/libiberty/cp-demangle.c |
+++ b/libiberty/cp-demangle.c |
@@ -275,6 +275,31 @@ 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 |
{ |
@@ -302,6 +327,12 @@ 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; |
+ /* 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 |
@@ -382,6 +413,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 * |
@@ -425,6 +459,10 @@ d_add_substitution (struct d_info *, struct demangle_component *); |
static struct demangle_component *d_substitution (struct d_info *, int); |
+static void d_checkpoint (struct d_info *, struct d_info_checkpoint *); |
+ |
+static void d_backtrack (struct d_info *, struct d_info_checkpoint *); |
+ |
static void d_growable_string_init (struct d_growable_string *, size_t); |
static inline void |
@@ -508,6 +546,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; |
@@ -609,6 +652,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; |
@@ -696,6 +745,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); |
@@ -803,6 +866,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: |
@@ -832,6 +896,8 @@ 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: |
@@ -871,6 +937,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; |
@@ -1109,6 +1177,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)); |
} |
} |
@@ -1164,7 +1234,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 |
@@ -1178,7 +1250,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; |
} |
@@ -1194,6 +1268,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> |
@@ -1220,7 +1311,6 @@ d_name (struct d_info *di) |
case 'Z': |
return d_local_name (di); |
- case 'L': |
case 'U': |
return d_unqualified_name (di); |
@@ -1267,6 +1357,7 @@ d_name (struct d_info *di) |
return dc; |
} |
+ case 'L': |
default: |
dc = d_unqualified_name (di); |
if (d_peek_char (di) == 'I') |
@@ -1283,8 +1374,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 * |
@@ -1292,6 +1383,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; |
@@ -1300,10 +1392,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; |
@@ -1408,15 +1510,14 @@ 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) |
{ |
@@ -1425,14 +1526,11 @@ d_unqualified_name (struct d_info *di) |
ret = d_make_comp (di, DEMANGLE_COMPONENT_UNARY, ret, |
d_source_name (di)); |
} |
- return ret; |
} |
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); |
@@ -1440,22 +1538,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> */ |
@@ -1582,11 +1685,13 @@ const struct demangle_operator_info cplus_demangle_operators[] = |
{ "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 }, |
+ { "dc", NL ("dynamic_cast"), 2 }, |
{ "de", NL ("*"), 1 }, |
{ "dl", NL ("delete "), 1 }, |
{ "ds", NL (".*"), 2 }, |
@@ -1626,8 +1731,10 @@ 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 }, |
{ "tr", NL ("throw"), 0 }, |
@@ -1646,8 +1753,15 @@ d_operator_name (struct d_info *di) |
if (c1 == 'v' && IS_DIGIT (c2)) |
return d_make_extended_operator (di, c2 - '0', d_source_name (di)); |
else if (c1 == 'c' && c2 == 'v') |
- return d_make_comp (di, DEMANGLE_COMPONENT_CAST, |
- cplus_demangle_type (di), NULL); |
+ { |
+ struct demangle_component *type; |
+ int was_conversion = di->is_conversion; |
+ |
+ di->is_conversion = ! di->is_expression; |
+ type = cplus_demangle_type (di); |
+ di->is_conversion = was_conversion; |
+ return d_make_comp (di, DEMANGLE_COMPONENT_CAST, type, NULL); |
+ } |
else |
{ |
/* LOW is the inclusive lower bound. */ |
@@ -1863,6 +1977,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; |
} |
@@ -2118,8 +2240,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; |
} |
@@ -2168,13 +2310,61 @@ cplus_demangle_type (struct d_info *di) |
ret = d_template_param (di); |
if (d_peek_char (di) == 'I') |
{ |
- /* This is <template-template-param> <template-args>. The |
- <template-template-param> part is a substitution |
+ /* This may be <template-template-param> <template-args>. |
+ If this is the type for a conversion operator, we can |
+ have a <template-template-param> here only by following |
+ a derivation like this: |
+ |
+ <nested-name> |
+ -> <template-prefix> <template-args> |
+ -> <prefix> <template-unqualified-name> <template-args> |
+ -> <unqualified-name> <template-unqualified-name> <template-args> |
+ -> <source-name> <template-unqualified-name> <template-args> |
+ -> <source-name> <operator-name> <template-args> |
+ -> <source-name> cv <type> <template-args> |
+ -> <source-name> cv <template-template-param> <template-args> <template-args> |
+ |
+ where the <template-args> is followed by another. |
+ Otherwise, we must have a derivation like this: |
+ |
+ <nested-name> |
+ -> <template-prefix> <template-args> |
+ -> <prefix> <template-unqualified-name> <template-args> |
+ -> <unqualified-name> <template-unqualified-name> <template-args> |
+ -> <source-name> <template-unqualified-name> <template-args> |
+ -> <source-name> <operator-name> <template-args> |
+ -> <source-name> cv <type> <template-args> |
+ -> <source-name> cv <template-param> <template-args> |
+ |
+ where we need to leave the <template-args> to be processed |
+ by d_prefix (following the <template-prefix>). |
+ |
+ The <template-template-param> part is a substitution |
candidate. */ |
- if (! d_add_substitution (di, ret)) |
- return NULL; |
- ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, |
- d_template_args (di)); |
+ if (! di->is_conversion) |
+ { |
+ if (! d_add_substitution (di, ret)) |
+ return NULL; |
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, |
+ d_template_args (di)); |
+ } |
+ else |
+ { |
+ struct demangle_component *args; |
+ struct d_info_checkpoint checkpoint; |
+ |
+ d_checkpoint (di, &checkpoint); |
+ args = d_template_args (di); |
+ if (d_peek_char (di) == 'I') |
+ { |
+ if (! d_add_substitution (di, ret)) |
+ return NULL; |
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, |
+ args); |
+ } |
+ else |
+ d_backtrack (di, &checkpoint); |
+ } |
} |
break; |
@@ -2422,7 +2612,38 @@ d_cv_qualifiers (struct d_info *di, |
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) |
@@ -2438,6 +2659,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; |
@@ -2460,6 +2683,10 @@ d_parmlist (struct d_info *di) |
char peek = d_peek_char (di); |
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) |
return NULL; |
@@ -2610,41 +2837,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); |
} |
@@ -2809,6 +3027,18 @@ d_exprlist (struct d_info *di, char terminator) |
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> |
@@ -2820,8 +3050,8 @@ d_exprlist (struct d_info *di, char terminator) |
::= <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; |
@@ -2849,7 +3079,7 @@ d_expression (struct d_info *di) |
{ |
d_advance (di, 2); |
return d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION, |
- d_expression (di), NULL); |
+ d_expression_1 (di), NULL); |
} |
else if (peek == 'f' && d_peek_next_char (di) == 'p') |
{ |
@@ -2954,7 +3184,7 @@ d_expression (struct d_info *di) |
&& d_check_char (di, '_')) |
operand = d_exprlist (di, 'E'); |
else |
- operand = d_expression (di); |
+ operand = d_expression_1 (di); |
if (suffix) |
/* Indicate the suffix variant for d_print_comp. */ |
@@ -2971,7 +3201,10 @@ d_expression (struct d_info *di) |
struct demangle_component *left; |
struct demangle_component *right; |
- 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, 'E'); |
else if (!strcmp (code, "dt") || !strcmp (code, "pt")) |
@@ -2982,7 +3215,7 @@ d_expression (struct d_info *di) |
right, d_template_args (di)); |
} |
else |
- right = d_expression (di); |
+ right = d_expression_1 (di); |
return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op, |
d_make_comp (di, |
@@ -2998,9 +3231,9 @@ d_expression (struct d_info *di) |
if (!strcmp (code, "qu")) |
{ |
/* ?: expression. */ |
- first = d_expression (di); |
- second = d_expression (di); |
- third = d_expression (di); |
+ first = d_expression_1 (di); |
+ second = d_expression_1 (di); |
+ third = d_expression_1 (di); |
} |
else if (code[0] == 'n') |
{ |
@@ -3024,7 +3257,7 @@ d_expression (struct d_info *di) |
else if (d_peek_char (di) == 'i' |
&& d_peek_next_char (di) == 'l') |
/* initializer-list. */ |
- third = d_expression (di); |
+ third = d_expression_1 (di); |
else |
return NULL; |
} |
@@ -3044,6 +3277,18 @@ d_expression (struct d_info *di) |
} |
} |
+static struct demangle_component * |
+d_expression (struct d_info *di) |
+{ |
+ struct demangle_component *ret; |
+ int was_expression = di->is_expression; |
+ |
+ di->is_expression = 1; |
+ ret = d_expression_1 (di); |
+ di->is_expression = was_expression; |
+ return ret; |
+} |
+ |
/* <expr-primary> ::= L <type> <(value) number> E |
::= L <type> <(value) float> E |
::= L <mangled-name> E |
@@ -3109,6 +3354,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 * |
@@ -3428,6 +3674,26 @@ d_substitution (struct d_info *di, int prefix) |
} |
} |
+static void |
+d_checkpoint (struct d_info *di, struct d_info_checkpoint *checkpoint) |
+{ |
+ checkpoint->n = di->n; |
+ checkpoint->next_comp = di->next_comp; |
+ checkpoint->next_sub = di->next_sub; |
+ checkpoint->did_subs = di->did_subs; |
+ checkpoint->expansion = di->expansion; |
+} |
+ |
+static void |
+d_backtrack (struct d_info *di, struct d_info_checkpoint *checkpoint) |
+{ |
+ di->n = checkpoint->n; |
+ di->next_comp = checkpoint->next_comp; |
+ di->next_sub = checkpoint->next_sub; |
+ di->did_subs = checkpoint->did_subs; |
+ di->expansion = checkpoint->expansion; |
+} |
+ |
/* Initialize a growable string. */ |
static void |
@@ -3521,6 +3787,31 @@ d_print_init (struct d_print_info *dpi, demangle_callbackref callback, |
dpi->opaque = opaque; |
dpi->demangle_failure = 0; |
+ |
+ dpi->saved_scopes = NULL; |
+ dpi->num_saved_scopes = 0; |
+ dpi->current_template = NULL; |
+} |
+ |
+/* Free a print information structure. */ |
+ |
+static void |
+d_print_free (struct d_print_info *dpi) |
+{ |
+ int i; |
+ |
+ for (i = 0; i < dpi->num_saved_scopes; i++) |
+ { |
+ struct d_print_template *ts, *tn; |
+ |
+ for (ts = dpi->saved_scopes[i].templates; ts != NULL; ts = tn) |
+ { |
+ tn = ts->next; |
+ free (ts); |
+ } |
+ } |
+ |
+ free (dpi->saved_scopes); |
} |
/* Indicate that an error occurred during printing, and test for error. */ |
@@ -3605,6 +3896,7 @@ cplus_demangle_print_callback (int options, |
demangle_callbackref callback, void *opaque) |
{ |
struct d_print_info dpi; |
+ int success; |
d_print_init (&dpi, callback, opaque); |
@@ -3612,7 +3904,9 @@ cplus_demangle_print_callback (int options, |
d_print_flush (&dpi); |
- return ! d_print_saw_error (&dpi); |
+ success = ! d_print_saw_error (&dpi); |
+ d_print_free (&dpi); |
+ return success; |
} |
/* Turn components into a human readable string. OPTIONS is the |
@@ -3710,6 +4004,7 @@ 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: |
@@ -3768,6 +4063,36 @@ d_print_subexpr (struct d_print_info *dpi, int options, |
d_append_char (dpi, ')'); |
} |
+/* Return a shallow copy of the current list of templates. |
+ On error d_print_error is called and a partial list may |
+ be returned. Whatever is returned must be freed. */ |
+ |
+static struct d_print_template * |
+d_copy_templates (struct d_print_info *dpi) |
+{ |
+ struct d_print_template *src, *result, **link = &result; |
+ |
+ for (src = dpi->templates; src != NULL; src = src->next) |
+ { |
+ struct d_print_template *dst = |
+ (struct d_print_template *) malloc (sizeof (struct d_print_template)); |
+ |
+ if (dst == NULL) |
+ { |
+ d_print_error (dpi); |
+ break; |
+ } |
+ |
+ dst->template_decl = src->template_decl; |
+ *link = dst; |
+ link = &dst->next; |
+ } |
+ |
+ *link = NULL; |
+ |
+ return result; |
+} |
+ |
/* Subroutine to handle components. */ |
static void |
@@ -3778,6 +4103,13 @@ d_print_comp (struct d_print_info *dpi, int options, |
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); |
@@ -3795,6 +4127,13 @@ d_print_comp (struct d_print_info *dpi, int options, |
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, options, d_left (dc)); |
@@ -3802,7 +4141,17 @@ d_print_comp (struct d_print_info *dpi, int options, |
d_append_string (dpi, "::"); |
else |
d_append_char (dpi, '.'); |
- d_print_comp (dpi, options, 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: |
@@ -3837,7 +4186,9 @@ d_print_comp (struct d_print_info *dpi, int options, |
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); |
@@ -3871,7 +4222,10 @@ d_print_comp (struct d_print_info *dpi, int options, |
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]) |
{ |
@@ -3918,6 +4272,12 @@ d_print_comp (struct d_print_info *dpi, int options, |
{ |
struct d_print_mod *hold_dpm; |
struct demangle_component *dcl; |
+ const struct demangle_component *hold_current; |
+ |
+ /* This template may need to be referenced by a cast operator |
+ contained in its subtree. */ |
+ hold_current = dpi->current_template; |
+ dpi->current_template = dc; |
/* Don't push modifiers into a template definition. Doing so |
could give the wrong definition for a template argument. |
@@ -3954,6 +4314,7 @@ d_print_comp (struct d_print_info *dpi, int options, |
} |
dpi->modifiers = hold_dpm; |
+ dpi->current_template = hold_current; |
return; |
} |
@@ -4053,6 +4414,16 @@ d_print_comp (struct d_print_info *dpi, int options, |
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 #"); |
d_print_comp (dpi, options, d_right (dc)); |
@@ -4114,12 +4485,58 @@ d_print_comp (struct d_print_info *dpi, int options, |
const struct demangle_component *sub = d_left (dc); |
if (sub->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM) |
{ |
- struct demangle_component *a = d_lookup_template_argument (dpi, sub); |
+ struct demangle_component *a; |
+ struct d_saved_scope *scope = NULL, *scopes; |
+ int i; |
+ |
+ for (i = 0; i < dpi->num_saved_scopes; i++) |
+ if (dpi->saved_scopes[i].container == sub) |
+ scope = &dpi->saved_scopes[i]; |
+ |
+ if (scope == NULL) |
+ { |
+ size_t size; |
+ |
+ /* 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. */ |
+ ++dpi->num_saved_scopes; |
+ size = sizeof (struct d_saved_scope) * dpi->num_saved_scopes; |
+ scopes = (struct d_saved_scope *) realloc (dpi->saved_scopes, |
+ size); |
+ if (scopes == NULL) |
+ { |
+ d_print_error (dpi); |
+ return; |
+ } |
+ |
+ dpi->saved_scopes = scopes; |
+ scope = dpi->saved_scopes + (dpi->num_saved_scopes - 1); |
+ |
+ scope->container = sub; |
+ scope->templates = d_copy_templates (dpi); |
+ 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; |
} |
@@ -4138,6 +4555,8 @@ d_print_comp (struct d_print_info *dpi, int options, |
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: |
@@ -4165,6 +4584,9 @@ d_print_comp (struct d_print_info *dpi, int options, |
dpi->modifiers = dpm.next; |
+ if (need_template_restore) |
+ dpi->templates = saved_templates; |
+ |
return; |
} |
@@ -4455,6 +4877,17 @@ d_print_comp (struct d_print_info *dpi, int options, |
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. */ |
@@ -4799,7 +5232,10 @@ d_print_mod_list (struct d_print_info *dpi, int options, |
|| (! 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, options, mods->next, suffix); |
return; |
@@ -4854,7 +5290,9 @@ d_print_mod_list (struct d_print_info *dpi, int options, |
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, options, dc); |
@@ -4899,9 +5337,14 @@ d_print_mod (struct d_print_info *dpi, int options, |
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; |
@@ -4973,6 +5416,8 @@ d_print_function_type (struct d_print_info *dpi, int options, |
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; |
@@ -5087,28 +5532,32 @@ static void |
d_print_cast (struct d_print_info *dpi, int options, |
const struct demangle_component *dc) |
{ |
- if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE) |
- d_print_comp (dpi, options, d_left (dc)); |
- else |
- { |
- struct d_print_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, ' '); |
@@ -5119,8 +5568,6 @@ d_print_cast (struct d_print_info *dpi, int options, |
if (d_last_char (dpi) == '>') |
d_append_char (dpi, ' '); |
d_append_char (dpi, '>'); |
- |
- dpi->modifiers = hold_dpm; |
} |
} |
@@ -5153,6 +5600,8 @@ cplus_demangle_init_info (const char *mangled, int options, size_t len, |
di->last_name = NULL; |
di->expansion = 0; |
+ di->is_expression = 0; |
+ di->is_conversion = 0; |
} |
/* Internal implementation for the demangler. If MANGLED is a g++ v3 ABI |
@@ -5493,14 +5942,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: |