From 5a4dbf7d315730cf6c94a67a42e8cc3a41047ff5 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Mon, 1 May 2017 22:51:04 +0000 Subject: [PATCH] d-demangle.c (dlang_parse_symbol): Remove function. libiberty/ChangeLog: * d-demangle.c (dlang_parse_symbol): Remove function. (dlang_parse_qualified): New function. (dlang_parse_mangle): New function. (dlang_type): Update to call dlang_parse_qualified. (dlang_identifier): Update to call either dlang_parse_qualified or dlang_parse_mangle. (dlang_type_modifier_p): Remove function. (dlang_call_convention_p): Don't allow type modifiers in mangle. (dlang_template_args): Update to call dlang_identifier. (dlang_demangle): Update to call dlang_parse_mangle. * testsuite/d-demangle-expected: Add tests. From-SVN: r247450 --- libiberty/ChangeLog | 14 ++ libiberty/d-demangle.c | 214 +++++++++++++----------- libiberty/testsuite/d-demangle-expected | 12 ++ 3 files changed, 142 insertions(+), 98 deletions(-) diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 7ae475488c4..fa2104dc866 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,17 @@ +2017-05-02 Iain Buclaw + + * d-demangle.c (dlang_parse_symbol): Remove function. + (dlang_parse_qualified): New function. + (dlang_parse_mangle): New function. + (dlang_type): Update to call dlang_parse_qualified. + (dlang_identifier): Update to call either dlang_parse_qualified or + dlang_parse_mangle. + (dlang_type_modifier_p): Remove function. + (dlang_call_convention_p): Don't allow type modifiers in mangle. + (dlang_template_args): Update to call dlang_identifier. + (dlang_demangle): Update to call dlang_parse_mangle. + * testsuite/d-demangle-expected: Add tests. + 2017-05-01 Iain Buclaw * d-demangle.c (dlang_value): Add comment explaining why cases for diff --git a/libiberty/d-demangle.c b/libiberty/d-demangle.c index 4d9b1102b70..f62cc63878c 100644 --- a/libiberty/d-demangle.c +++ b/libiberty/d-demangle.c @@ -186,7 +186,10 @@ static const char *dlang_type (string *, const char *); static const char *dlang_value (string *, const char *, const char *, char); -static const char *dlang_parse_symbol (string *, const char *, +static const char *dlang_parse_qualified (string *, const char *, + enum dlang_symbol_kinds); + +static const char *dlang_parse_mangle (string *, const char *, enum dlang_symbol_kinds); static const char *dlang_parse_tuple (string *, const char *); @@ -561,7 +564,7 @@ dlang_type (string *decl, const char *mangled) case 'E': /* enum T */ case 'T': /* typedef T */ mangled++; - return dlang_parse_symbol (decl, mangled, dlang_type_name); + return dlang_parse_qualified (decl, mangled, dlang_type_name); case 'D': /* delegate T */ { string mods; @@ -743,12 +746,10 @@ dlang_identifier (string *decl, const char *mangled, /* Check whether template parameter is a function with a valid return type or an untyped identifier. */ if (ISDIGIT (*mangled)) - mangled = dlang_parse_symbol (decl, mangled, dlang_template_ident); + mangled = dlang_parse_qualified (decl, mangled, + dlang_template_ident); else if (strncmp (mangled, "_D", 2) == 0) - { - mangled += 2; - mangled = dlang_parse_symbol (decl, mangled, dlang_function); - } + mangled = dlang_parse_mangle (decl, mangled, dlang_function); /* Check for name length mismatch. */ if (mangled && (mangled - pend) == psize) @@ -1299,49 +1300,11 @@ dlang_value (string *decl, const char *mangled, const char *name, char type) return mangled; } -/* Extract the type modifiers from MANGLED and return the string - length that it consumes in MANGLED on success or 0 on failure. */ -static int -dlang_type_modifier_p (const char *mangled) -{ - int i; - - switch (*mangled) - { - case 'x': case 'y': - return 1; - - case 'O': - mangled++; - i = dlang_type_modifier_p (mangled); - return i + 1; - - case 'N': - mangled++; - if (*mangled == 'g') - { - mangled++; - i = dlang_type_modifier_p (mangled); - return i + 2; - } - } - - return 0; -} - /* Extract the function calling convention from MANGLED and return 1 on success or 0 on failure. */ static int dlang_call_convention_p (const char *mangled) { - /* Prefix for functions needing 'this' */ - if (*mangled == 'M') - { - mangled++; - /* Also skip over any type modifiers. */ - mangled += dlang_type_modifier_p (mangled); - } - switch (*mangled) { case 'F': case 'U': case 'V': @@ -1356,10 +1319,94 @@ dlang_call_convention_p (const char *mangled) /* Extract and demangle the symbol in MANGLED and append it to DECL. Returns the remaining signature on success or NULL on failure. */ static const char * -dlang_parse_symbol (string *decl, const char *mangled, +dlang_parse_mangle (string *decl, const char *mangled, enum dlang_symbol_kinds kind) { - int saved; + /* A D mangled symbol is comprised of both scope and type information. + + MangleName: + _D QualifiedName Type + _D QualifiedName M Type + _D QualifiedName Z + ^ + The caller should have guaranteed that the start pointer is at the + above location. + */ + mangled += 2; + + mangled = dlang_parse_qualified (decl, mangled, dlang_top_level); + + if (mangled != NULL) + { + /* Artificial symbols end with 'Z' and have no type. */ + if (*mangled == 'Z') + mangled++; + else + { + string mods; + int saved; + + /* Skip over 'this' parameter. */ + if (*mangled == 'M') + mangled++; + + /* Save the type modifiers for appending at the end if needed. */ + string_init (&mods); + mangled = dlang_type_modifiers (&mods, mangled); + + if (mangled && dlang_call_convention_p (mangled)) + { + /* Skip over calling convention and attributes. */ + saved = string_length (decl); + mangled = dlang_call_convention (decl, mangled); + mangled = dlang_attributes (decl, mangled); + string_setlength (decl, saved); + + string_append (decl, "("); + mangled = dlang_function_args (decl, mangled); + string_append (decl, ")"); + + /* Add any const/immutable/shared modifier. */ + string_appendn (decl, mods.b, string_length (&mods)); + } + + /* Consume the decl type of symbol. */ + saved = string_length (decl); + mangled = dlang_type (decl, mangled); + string_setlength (decl, saved); + + string_delete (&mods); + } + } + + /* Check that the entire symbol was successfully demangled. */ + if (kind == dlang_top_level) + { + if (mangled == NULL || *mangled != '\0') + return NULL; + } + + return mangled; +} + +/* Extract and demangle the qualified symbol in MANGLED and append it to DECL. + Returns the remaining signature on success or NULL on failure. */ +static const char * +dlang_parse_qualified (string *decl, const char *mangled, + enum dlang_symbol_kinds kind) +{ + /* Qualified names are identifiers separated by their encoded length. + Nested functions also encode their argument types without specifying + what they return. + + QualifiedName: + SymbolName + SymbolName QualifiedName + SymbolName TypeFunctionNoReturn QualifiedName + SymbolName M TypeModifiers TypeFunctionNoReturn QualifiedName + ^ + The start pointer should be at the above location. + */ size_t n = 0; do { @@ -1372,32 +1419,30 @@ dlang_parse_symbol (string *decl, const char *mangled, mangled = dlang_identifier (decl, mangled, kind); - if (mangled && dlang_call_convention_p (mangled)) + /* Consume the encoded arguments. However if this is not followed by the + next encoded length, then this is not a continuation of a qualified + name, in which case we backtrack and return the current unconsumed + position of the mangled decl. */ + if (mangled && (*mangled == 'M' || dlang_call_convention_p (mangled))) { - string mods; - const char *start = NULL; - int checkpoint = 0; + const char *start = mangled; + int saved = string_length (decl); - /* Skip over 'this' parameter. */ + /* Skip over 'this' parameter and type modifiers. */ if (*mangled == 'M') - mangled++; - - /* We have reached here because we expect an extern(Pascal) function. - However this is so rare, that it is more likely a template value - parameter. Since this can't be assumed, first attempt parsing - the symbol as a function, and then back out on failure. */ - if (*mangled == 'V') { - start = mangled; - checkpoint = string_length (decl); + mangled++; + mangled = dlang_type_modifiers (decl, mangled); + string_setlength (decl, saved); } - /* Save the type modifiers for appending at the end. */ - string_init (&mods); - mangled = dlang_type_modifiers (&mods, mangled); + /* The rule we expect to match in the mangled string is: - /* Skip over calling convention and attributes in qualified name. */ - saved = string_length (decl); + TypeFunctionNoReturn: + CallConvention FuncAttrs Arguments ArgClose + + The calling convention and function attributes are not included + in the demangled string. */ mangled = dlang_call_convention (decl, mangled); mangled = dlang_attributes (decl, mangled); string_setlength (decl, saved); @@ -1406,41 +1451,16 @@ dlang_parse_symbol (string *decl, const char *mangled, mangled = dlang_function_args (decl, mangled); string_append (decl, ")"); - /* Add any const/immutable/shared modifier. */ - string_appendn (decl, mods.b, string_length (&mods)); - string_delete (&mods); - - if (mangled == NULL && checkpoint != 0) + if (mangled == NULL || !ISDIGIT (*mangled)) { + /* Did not match the rule we were looking for. */ mangled = start; - string_setlength (decl, checkpoint); + string_setlength (decl, saved); } } } while (mangled && ISDIGIT (*mangled)); - /* Only top-level symbols or function template parameters have - a type that needs checking. */ - if (kind == dlang_top_level || kind == dlang_function) - { - /* Artificial symbols end with 'Z' and have no type. */ - if (mangled && *mangled == 'Z') - mangled++; - else - { - saved = string_length (decl); - mangled = dlang_type (decl, mangled); - string_setlength (decl, saved); - } - - /* Check that the entire symbol was successfully demangled. */ - if (kind == dlang_top_level) - { - if (mangled == NULL || *mangled != '\0') - return NULL; - } - } - return mangled; } @@ -1496,7 +1516,7 @@ dlang_template_args (string *decl, const char *mangled) { case 'S': /* Symbol parameter. */ mangled++; - mangled = dlang_parse_symbol (decl, mangled, dlang_template_param); + mangled = dlang_identifier (decl, mangled, dlang_template_param); break; case 'T': /* Type parameter. */ mangled++; @@ -1594,9 +1614,7 @@ dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED) } else { - mangled += 2; - - if (dlang_parse_symbol (&decl, mangled, dlang_top_level) == NULL) + if (dlang_parse_mangle (&decl, mangled, dlang_top_level) == NULL) string_delete (&decl); } diff --git a/libiberty/testsuite/d-demangle-expected b/libiberty/testsuite/d-demangle-expected index c64fcc60c27..76cb208c81b 100644 --- a/libiberty/testsuite/d-demangle-expected +++ b/libiberty/testsuite/d-demangle-expected @@ -22,6 +22,14 @@ _D8demangle4testPFLAiYi demangle.test # --format=dlang +_D8demangle4testFZv +demangle.test() +# +--format=dlang +_D8demangle4testMFZ2fnMFZv +demangle.test().fn() +# +--format=dlang _D8demangle4testFaZv demangle.test(char) # @@ -1108,6 +1116,10 @@ _D8demangle29__T2fnVa97Va9Va0Vu257Vw65537Z2fnFZv demangle.fn!('a', '\x09', '\x00', '\u0101', '\U00010001').fn() # --format=dlang +_D8demangle32__T2fnTS3symVS3valS1a4_6e756c6cZ3fun13__T8positionZ13__T8confusesZ8demangleFDFxaZvZv +demangle.fn!(sym, val("null")).fun.position!().confuses!().demangle(void(const(char)) delegate) +# +--format=dlang _D2gc11gctemplates56__T8mkBitmapTS3std5range13__T4iotaTiTiZ4iotaFiiZ6ResultZ8mkBitmapFNbNiNfPmmZv gc.gctemplates.mkBitmap!(std.range.iota!(int, int).iota(int, int).Result).mkBitmap(ulong*, ulong) # -- 2.30.2