-- v4: ucrtbase: Handle undecoration of function's reference qualifiers (C++11). msvcrt: Rename modifier into qualifier. ucrtbase: Extend ucrtbase's undname tests.
From: Eric Pouech eric.pouech@gmail.com
Renumbering entries' comment to match actual output. Adding ability to pass flags.
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/ucrtbase/tests/cpp.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-)
diff --git a/dlls/ucrtbase/tests/cpp.c b/dlls/ucrtbase/tests/cpp.c index a22138889cb..b9b36a1e740 100644 --- a/dlls/ucrtbase/tests/cpp.c +++ b/dlls/ucrtbase/tests/cpp.c @@ -192,21 +192,36 @@ static void test___std_type_info(void)
static void test___unDName(void) { - static struct {const char *in; const char *out; const char *broken;} und_tests[] = + static struct {const char *in; const char *out; const char *broken; unsigned int flags;} und_tests[] = { -/* 1 */ {"??4QDnsDomainNameRecord@@QAEAAV0@$$QAV0@@Z", +/* 0 */ {"??4QDnsDomainNameRecord@@QAEAAV0@$$QAV0@@Z", "public: class QDnsDomainNameRecord & __thiscall QDnsDomainNameRecord::operator=(class QDnsDomainNameRecord &&)"}, -/* 2 */ {"??4QDnsDomainNameRecord@@QAEAAV0@$$QEAV0@@Z", +/* 1 */ {"??4QDnsDomainNameRecord@@QAEAAV0@$$QEAV0@@Z", "public: class QDnsDomainNameRecord & __thiscall QDnsDomainNameRecord::operator=(class QDnsDomainNameRecord && __ptr64)"}, -/* 3 */ {"??__K_l@@YA?AUCC@@I@Z", "struct CC __cdecl operator "" _l(unsigned int)", +/* 2 */ {"??__K_l@@YA?AUCC@@I@Z", "struct CC __cdecl operator "" _l(unsigned int)", "??__K_l@@YA?AUCC@@I@Z" /* W10 1507 fails on this :-( */}, +/* 3 */ {"?meth@Q@@QEGBA?AV1@XZ", + "public: class Q __cdecl Q::meth(void)const __ptr64& ", + "public: ?? :: ?? ::XZ::V1" /* W10 1507 fails on this :-( */}, +/* 4 */ {"?meth@Q@@QEHAA?AV1@XZ", + "public: class Q __cdecl Q::meth(void) __ptr64&& ", + "public: ?? :: ?? ::XZ::V1" /* W10 1507 fails on this :-( */}, +/* 5 */ {"?meth@Q@@QEGBA?AV1@XZ", + "public: class Q Q::meth(void)const & ", + "public: ?? :: ?? ::XZ::V1" /* W10 1507 fails on this :-( */, + 0x02 /*UNDNAME_NO_MS_KEYWORDS*/}, +/* 6 */ {"?meth@Q@@QEHAA?AV1@XZ", + "public: class Q Q::meth(void)&& ", + "public: ?? :: ?? ::XZ::V1" /* W10 1507 fails on this :-( */, + 0x02 /*UNDNAME_NO_MS_KEYWORDS*/}, }; unsigned i; for (i = 0; i < ARRAY_SIZE(und_tests); i++) { - char *name = p___unDName(0, und_tests[i].in, 0, malloc, free, 0); + char *name = p___unDName(0, und_tests[i].in, 0, malloc, free, und_tests[i].flags); + todo_wine_if(i >= 3) ok(!strcmp(name, und_tests[i].out) || - (broken(und_tests[i].broken && !strcmp(und_tests[i].broken, name))), + broken(und_tests[i].broken && !strcmp(und_tests[i].broken, name)), "unDName returned %s for #%u\n", wine_dbgstr_a(name), i); free(name); }
From: Eric Pouech eric.pouech@gmail.com
That's how they are defined in C/C++ standard.
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/undname.c | 106 +++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 53 deletions(-)
diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index eb95da98435..8db8e8f01b9 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -33,8 +33,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); * - back-port this new code into tools/winedump/msmangle.c */
-/* How data types modifiers are stored: - * M (in the following definitions) is defined for +/* How data types qualifiers are stored: + * M (in the following definitions) is defined for * 'A', 'B', 'C' and 'D' as follows * {<A>}: "" * {<B>}: "const " @@ -407,7 +407,7 @@ static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_t return args_str; }
-static void append_extended_modifier(struct parsed_symbol *sym, const char **where, const char *str) +static void append_extended_qualifier(struct parsed_symbol *sym, const char **where, const char *str) { if (!(sym->flags & UNDNAME_NO_MS_KEYWORDS)) { @@ -417,7 +417,7 @@ static void append_extended_modifier(struct parsed_symbol *sym, const char **whe } }
-static void get_extended_modifier(struct parsed_symbol *sym, struct datatype_t *xdt) +static void get_extended_qualifier(struct parsed_symbol *sym, struct datatype_t *xdt) { xdt->left = xdt->right = NULL; xdt->flags = 0; @@ -425,9 +425,9 @@ static void get_extended_modifier(struct parsed_symbol *sym, struct datatype_t * { switch (*sym->current) { - case 'E': append_extended_modifier(sym, &xdt->right, "__ptr64"); break; - case 'F': append_extended_modifier(sym, &xdt->left, "__unaligned"); break; - case 'I': append_extended_modifier(sym, &xdt->right, "__restrict"); break; + case 'E': append_extended_qualifier(sym, &xdt->right, "__ptr64"); break; + case 'F': append_extended_qualifier(sym, &xdt->left, "__unaligned"); break; + case 'I': append_extended_qualifier(sym, &xdt->right, "__restrict"); break; default: return; } sym->current++; @@ -435,29 +435,29 @@ static void get_extended_modifier(struct parsed_symbol *sym, struct datatype_t * }
/****************************************************************** - * get_modifier - * Parses the type modifier. Always returns static strings. + * get_qualifier + * Parses the type qualifier. Always returns static strings. */ -static BOOL get_modifier(struct parsed_symbol *sym, struct datatype_t *xdt, const char** pclass) +static BOOL get_qualifier(struct parsed_symbol *sym, struct datatype_t *xdt, const char** pclass) { char ch; - const char* mod; + const char* qualif;
- get_extended_modifier(sym, xdt); + get_extended_qualifier(sym, xdt); switch (ch = *sym->current++) { - case 'A': mod = NULL; break; - case 'B': mod = "const"; break; - case 'C': mod = "volatile"; break; - case 'D': mod = "const volatile"; break; - case 'Q': mod = NULL; break; - case 'R': mod = "const"; break; - case 'S': mod = "volatile"; break; - case 'T': mod = "const volatile"; break; + case 'A': qualif = NULL; break; + case 'B': qualif = "const"; break; + case 'C': qualif = "volatile"; break; + case 'D': qualif = "const volatile"; break; + case 'Q': qualif = NULL; break; + case 'R': qualif = "const"; break; + case 'S': qualif = "volatile"; break; + case 'T': qualif = "const volatile"; break; default: return FALSE; } - if (mod) - xdt->left = xdt->left ? str_printf(sym, "%s %s", mod, xdt->left) : mod; + if (qualif) + xdt->left = xdt->left ? str_printf(sym, "%s %s", qualif, xdt->left) : qualif; if (ch >= 'Q' && ch <= 'T') /* pointer to member, fetch class */ { const char* class = get_class_name(sym); @@ -473,48 +473,48 @@ static BOOL get_modifier(struct parsed_symbol *sym, struct datatype_t *xdt, cons return TRUE; }
-static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, - struct array *pmt_ref, char modif, enum datatype_flags flags) +static BOOL get_qualified_type(struct datatype_t *ct, struct parsed_symbol* sym, + struct array *pmt_ref, char qualif, enum datatype_flags flags) { struct datatype_t xdt1; struct datatype_t xdt2; const char* ref; - const char* str_modif; + const char* str_qualif; const char* class;
- get_extended_modifier(sym, &xdt1); + get_extended_qualifier(sym, &xdt1);
- switch (modif) + switch (qualif) { - case 'A': ref = " &"; str_modif = NULL; break; - case 'B': ref = " &"; str_modif = " volatile"; break; - case 'P': ref = " *"; str_modif = NULL; break; - case 'Q': ref = " *"; str_modif = " const"; break; - case 'R': ref = " *"; str_modif = " volatile"; break; - case 'S': ref = " *"; str_modif = " const volatile"; break; - case '?': ref = NULL; str_modif = NULL; break; - case '$': ref = " &&"; str_modif = NULL; break; + case 'A': ref = " &"; str_qualif = NULL; break; + case 'B': ref = " &"; str_qualif = " volatile"; break; + case 'P': ref = " *"; str_qualif = NULL; break; + case 'Q': ref = " *"; str_qualif = " const"; break; + case 'R': ref = " *"; str_qualif = " volatile"; break; + case 'S': ref = " *"; str_qualif = " const volatile"; break; + case '?': ref = NULL; str_qualif = NULL; break; + case '$': ref = " &&"; str_qualif = NULL; break; default: return FALSE; } ct->right = NULL; ct->flags = 0;
- if (get_modifier(sym, &xdt2, &class)) + if (get_qualifier(sym, &xdt2, &class)) { unsigned mark = sym->stack.num; struct datatype_t sub_ct;
- if (ref || str_modif || xdt1.left || xdt1.right) + if (ref || str_qualif || xdt1.left || xdt1.right) { if (class) ct->left = str_printf(sym, "%s%s%s%s::%s%s%s", xdt1.left ? " " : NULL, xdt1.left, class ? " " : NULL, class, ref ? ref + 1 : NULL, - xdt1.right ? " " : NULL, xdt1.right, str_modif); + xdt1.right ? " " : NULL, xdt1.right, str_qualif); else ct->left = str_printf(sym, "%s%s%s%s%s%s", xdt1.left ? " " : NULL, xdt1.left, ref, - xdt1.right ? " " : NULL, xdt1.right, str_modif); + xdt1.right ? " " : NULL, xdt1.right, str_qualif); } else ct->left = NULL; @@ -543,14 +543,14 @@ static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym, ct->left++; ct->left = str_printf(sym, "%s%s%s%s%s", sub_ct.left, xdt2.left ? " " : NULL, xdt2.left, ct->left, - ((xdt2.left || str_modif) && (flags & WS_AFTER_QUAL_IF)) ? " " : NULL); + ((xdt2.left || str_qualif) && (flags & WS_AFTER_QUAL_IF)) ? " " : NULL); if (sub_ct.right) ct->right = str_printf(sym, "%s%s", ct->right, sub_ct.right); sym->stack.num = mark; } - else if (ref || str_modif || xdt1.left || xdt1.right) + else if (ref || str_qualif || xdt1.left || xdt1.right) ct->left = str_printf(sym, "%s%s%s%s%s%s", xdt1.left ? " " : NULL, xdt1.left, ref, - xdt1.right ? " " : NULL, xdt1.right, str_modif); + xdt1.right ? " " : NULL, xdt1.right, str_qualif); else ct->left = NULL; return TRUE; @@ -926,17 +926,17 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, } else { - if (!get_modified_type(ct, sym, pmt_ref, '?', flags)) goto done; + if (!get_qualified_type(ct, sym, pmt_ref, '?', flags)) goto done; } break; case 'A': /* reference */ case 'B': /* volatile reference */ - if (!get_modified_type(ct, sym, pmt_ref, dt, flags)) goto done; + if (!get_qualified_type(ct, sym, pmt_ref, dt, flags)) goto done; break; case 'Q': /* const pointer */ case 'R': /* volatile pointer */ case 'S': /* const volatile pointer */ - if (!get_modified_type(ct, sym, pmt_ref, (flags & IN_ARGS) ? dt : 'P', flags)) goto done; + if (!get_qualified_type(ct, sym, pmt_ref, (flags & IN_ARGS) ? dt : 'P', flags)) goto done; break; case 'P': /* Pointer */ if (isdigit(*sym->current)) @@ -955,7 +955,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
if (!(class = get_class_name(sym))) goto done; - if (!get_modifier(sym, &xdt, NULL)) + if (!get_qualifier(sym, &xdt, NULL)) goto done; if (!get_function_signature(sym, pmt_ref, &fs)) goto done; @@ -984,7 +984,7 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, } else goto done; } - else if (!get_modified_type(ct, sym, pmt_ref, 'P', flags)) goto done; + else if (!get_qualified_type(ct, sym, pmt_ref, 'P', flags)) goto done; break; case 'W': if (*sym->current == '4') @@ -1101,14 +1101,14 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, struct datatype_t xdt;
sym->current++; - if (!get_modifier(sym, &xdt, NULL)) goto done; + if (!get_qualifier(sym, &xdt, NULL)) goto done; if (!demangle_datatype(sym, ct, pmt_ref, flags)) goto done; ct->left = str_printf(sym, "%s %s", ct->left, xdt.left); } else if (*sym->current == 'Q') { sym->current++; - if (!get_modified_type(ct, sym, pmt_ref, '$', flags)) goto done; + if (!get_qualified_type(ct, sym, pmt_ref, '$', flags)) goto done; } break; } @@ -1184,7 +1184,7 @@ static BOOL handle_data(struct parsed_symbol* sym) str_array_init(&pmt);
if (!demangle_datatype(sym, &ct, &pmt, 0)) goto done; - if (!get_modifier(sym, &xdt, &class)) goto done; /* class doesn't seem to be displayed */ + if (!get_qualifier(sym, &xdt, &class)) goto done; /* class doesn't seem to be displayed */ if (xdt.left && xdt.right) xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right); else if (!xdt.left) xdt.left = xdt.right; sym->stack.num = mark; @@ -1193,7 +1193,7 @@ static BOOL handle_data(struct parsed_symbol* sym) case '6' : /* compiler generated static */ case '7' : /* compiler generated static */ ct.left = ct.right = NULL; - if (!get_modifier(sym, &xdt, NULL)) goto done; + if (!get_qualifier(sym, &xdt, NULL)) goto done; if (*sym->current != '@') { char* cls = NULL; @@ -1362,8 +1362,8 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) (accmem <= 'X' && (accmem - 'A') % 8 != 2 && (accmem - 'A') % 8 != 3))) { /* Implicit 'this' pointer */ - /* If there is an implicit this pointer, const modifier follows */ - if (!get_modifier(sym, &xdt, NULL)) goto done; + /* If there is an implicit this pointer, const qualifier follows */ + if (!get_qualifier(sym, &xdt, NULL)) goto done; if (xdt.left || xdt.right) xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right); }
From: Eric Pouech eric.pouech@gmail.com
Introducing get_function_qualifier(). Feature is not available in msvcrt.
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/msvcrt/undname.c | 59 ++++++++++++++++++++++++--------------- dlls/ucrtbase/tests/cpp.c | 1 - 2 files changed, 37 insertions(+), 23 deletions(-)
diff --git a/dlls/msvcrt/undname.c b/dlls/msvcrt/undname.c index 8db8e8f01b9..5a7283caac7 100644 --- a/dlls/msvcrt/undname.c +++ b/dlls/msvcrt/undname.c @@ -80,6 +80,7 @@ struct parsed_symbol enum datatype_e { DT_NO_LEADING_WS = 0x01, + DT_NO_LRSEP_WS = 0x02, };
/* Type for parsing mangled types */ @@ -407,28 +408,35 @@ static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_t return args_str; }
-static void append_extended_qualifier(struct parsed_symbol *sym, const char **where, const char *str) +static void append_extended_qualifier(struct parsed_symbol *sym, const char **where, + const char *str, BOOL is_ms_keyword) { - if (!(sym->flags & UNDNAME_NO_MS_KEYWORDS)) + if (!is_ms_keyword || !(sym->flags & UNDNAME_NO_MS_KEYWORDS)) { - if (sym->flags & UNDNAME_NO_LEADING_UNDERSCORES) + if (is_ms_keyword && (sym->flags & UNDNAME_NO_LEADING_UNDERSCORES)) str += 2; - *where = *where ? str_printf(sym, "%s %s", *where, str) : str; + *where = *where ? str_printf(sym, "%s%s%s%s", *where, is_ms_keyword ? " " : "", str, is_ms_keyword ? "" : " ") : + str_printf(sym, "%s%s", str, is_ms_keyword ? "" : " "); } }
static void get_extended_qualifier(struct parsed_symbol *sym, struct datatype_t *xdt) { + unsigned fl = 0; xdt->left = xdt->right = NULL; xdt->flags = 0; for (;;) { switch (*sym->current) { - case 'E': append_extended_qualifier(sym, &xdt->right, "__ptr64"); break; - case 'F': append_extended_qualifier(sym, &xdt->left, "__unaligned"); break; - case 'I': append_extended_qualifier(sym, &xdt->right, "__restrict"); break; - default: return; + case 'E': append_extended_qualifier(sym, &xdt->right, "__ptr64", TRUE); fl |= 2; break; + case 'F': append_extended_qualifier(sym, &xdt->left, "__unaligned", TRUE); fl |= 2; break; +#ifdef _UCRT + case 'G': append_extended_qualifier(sym, &xdt->right, "&", FALSE); fl |= 1; break; + case 'H': append_extended_qualifier(sym, &xdt->right, "&&", FALSE); fl |= 1; break; +#endif + case 'I': append_extended_qualifier(sym, &xdt->right, "__restrict", TRUE); fl |= 2; break; + default: if (fl == 1 || (fl == 3 && (sym->flags & UNDNAME_NO_MS_KEYWORDS))) xdt->flags = DT_NO_LRSEP_WS; return; } sym->current++; } @@ -457,7 +465,10 @@ static BOOL get_qualifier(struct parsed_symbol *sym, struct datatype_t *xdt, con default: return FALSE; } if (qualif) + { + xdt->flags &= ~DT_NO_LRSEP_WS; xdt->left = xdt->left ? str_printf(sym, "%s %s", qualif, xdt->left) : qualif; + } if (ch >= 'Q' && ch <= 'T') /* pointer to member, fetch class */ { const char* class = get_class_name(sym); @@ -473,6 +484,16 @@ static BOOL get_qualifier(struct parsed_symbol *sym, struct datatype_t *xdt, con return TRUE; }
+static BOOL get_function_qualifier(struct parsed_symbol *sym, const char** qualif) +{ + struct datatype_t xdt; + + if (!get_qualifier(sym, &xdt, NULL)) return FALSE; + *qualif = (xdt.left || xdt.right) ? + str_printf(sym, "%s%s%s", xdt.left, (xdt.flags & DT_NO_LRSEP_WS) ? "" : " ", xdt.right) : NULL; + return TRUE; +} + static BOOL get_qualified_type(struct datatype_t *ct, struct parsed_symbol* sym, struct array *pmt_ref, char qualif, enum datatype_flags flags) { @@ -949,24 +970,20 @@ static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct, { struct function_signature fs; const char* class; - struct datatype_t xdt; + const char* function_qualifier;
sym->current++;
if (!(class = get_class_name(sym))) goto done; - if (!get_qualifier(sym, &xdt, NULL)) + if (!get_function_qualifier(sym, &function_qualifier)) goto done; if (!get_function_signature(sym, pmt_ref, &fs)) goto done; - if (xdt.left) - xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right); - else if (xdt.right) - xdt.left = str_printf(sym, " %s", xdt.right);
ct->left = str_printf(sym, "%s%s (%s %s::*", fs.return_ct.left, fs.return_ct.right, fs.call_conv, class); - ct->right = str_printf(sym, ")%s%s", fs.arguments, xdt.left); + ct->right = str_printf(sym, ")%s%s", fs.arguments, function_qualifier); } else if (*sym->current == '6') { @@ -1233,7 +1250,7 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) const char* member_type = NULL; struct datatype_t ct_ret; const char* call_conv; - struct datatype_t xdt = {NULL}; + const char* function_qualifier = NULL; const char* exported; const char* args_str = NULL; const char* name = NULL; @@ -1362,9 +1379,7 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) (accmem <= 'X' && (accmem - 'A') % 8 != 2 && (accmem - 'A') % 8 != 3))) { /* Implicit 'this' pointer */ - /* If there is an implicit this pointer, const qualifier follows */ - if (!get_qualifier(sym, &xdt, NULL)) goto done; - if (xdt.left || xdt.right) xdt.left = str_printf(sym, "%s %s", xdt.left, xdt.right); + if (!get_function_qualifier(sym, &function_qualifier)) goto done; }
if (!get_calling_convention(*sym->current++, &call_conv, &exported, @@ -1395,8 +1410,8 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op)
mark = sym->stack.num; if (has_args && !(args_str = get_args(sym, &array_pmt, TRUE, '(', ')'))) goto done; - if (sym->flags & UNDNAME_NAME_ONLY) args_str = xdt.left = NULL; - if (sym->flags & UNDNAME_NO_THISTYPE) xdt.left = NULL; + if (sym->flags & UNDNAME_NAME_ONLY) args_str = function_qualifier = NULL; + if (sym->flags & UNDNAME_NO_THISTYPE) function_qualifier = NULL; sym->stack.num = mark;
/* Note: '()' after 'Z' means 'throws', but we don't care here @@ -1406,7 +1421,7 @@ static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op) access, member_type, ct_ret.left, (ct_ret.left && !ct_ret.right) ? " " : NULL, call_conv, call_conv ? " " : NULL, exported, - name, args_str, xdt.left, ct_ret.right); + name, args_str, function_qualifier, ct_ret.right); ret = TRUE; done: return ret; diff --git a/dlls/ucrtbase/tests/cpp.c b/dlls/ucrtbase/tests/cpp.c index b9b36a1e740..9a66d66d814 100644 --- a/dlls/ucrtbase/tests/cpp.c +++ b/dlls/ucrtbase/tests/cpp.c @@ -219,7 +219,6 @@ static void test___unDName(void) for (i = 0; i < ARRAY_SIZE(und_tests); i++) { char *name = p___unDName(0, und_tests[i].in, 0, malloc, free, und_tests[i].flags); - todo_wine_if(i >= 3) ok(!strcmp(name, und_tests[i].out) || broken(und_tests[i].broken && !strcmp(und_tests[i].broken, name)), "unDName returned %s for #%u\n", wine_dbgstr_a(name), i);
This merge request was approved by Piotr Caban.