commit 0707fcaee20275a8955ab5741df70831c8e9e350 Author: Jason Merrill Date: Sat Apr 25 07:45:02 2015 -0400 PR c++/44282 gcc/cp/ * mangle.c (attr_strcmp): New. (write_CV_qualifiers_for_type): Also write out attributes that affect type identity. (write_type): Strip all attributes after writing qualifiers. libiberty/ * cp-demangle.c (cplus_demangle_type): Handle arguments to vendor extended qualifier. diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index e9eb511..748306b 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -894,7 +894,7 @@ c_common_post_options (const char **pfilename) /* Change flag_abi_version to be the actual current ABI level for the benefit of c_cpp_builtins. */ if (flag_abi_version == 0) - flag_abi_version = 8; + flag_abi_version = 9; /* Set C++ standard to C++98 if not specified on the command line. */ if (c_dialect_cxx () && cxx_dialect == cxx_unset) diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 647ec70..8151179 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -75,6 +75,7 @@ along with GCC; see the file COPYING3. If not see #include "ipa-ref.h" #include "cgraph.h" #include "wide-int.h" +#include "attribs.h" /* Debugging support. */ @@ -1916,11 +1917,15 @@ write_type (tree type) candidates. */ { tree t = TYPE_MAIN_VARIANT (type); + if (TYPE_ATTRIBUTES (t) && !OVERLOAD_TYPE_P (t)) + t = cp_build_type_attribute_variant (t, NULL_TREE); + gcc_assert (t != type); if (TREE_CODE (t) == FUNCTION_TYPE || TREE_CODE (t) == METHOD_TYPE) { t = build_ref_qualified_type (t, type_memfn_rqual (type)); - if (abi_version_at_least (8)) + if (abi_version_at_least (8) + || type == TYPE_MAIN_VARIANT (type)) /* Avoid adding the unqualified function type as a substitution. */ write_function_type (t); else @@ -2168,6 +2173,20 @@ write_type (tree type) add_substitution (type); } +/* qsort callback for sorting a vector of attribute entries. */ + +static int +attr_strcmp (const void *p1, const void *p2) +{ + tree a1 = *(const tree*)p1; + tree a2 = *(const tree*)p2; + + const attribute_spec *as1 = lookup_attribute_spec (get_attribute_name (a1)); + const attribute_spec *as2 = lookup_attribute_spec (get_attribute_name (a2)); + + return strcmp (as1->name, as2->name); +} + /* Non-terminal for type nodes. Returns the number of CV-qualifiers written for TYPE. @@ -2182,9 +2201,55 @@ write_CV_qualifiers_for_type (const tree type) "In cases where multiple order-insensitive qualifiers are present, they should be ordered 'K' (closest to the base type), - 'V', 'r', and 'U' (farthest from the base type) ..." + 'V', 'r', and 'U' (farthest from the base type) ..." */ - Note that we do not use cp_type_quals below; given "const + /* Mangle attributes that affect type identity as extended qualifiers. + + We mangle them onto the obstack, then copy the result into a string + vector and back up the obstack. Once we've handled all of them we + sort them and write them out in order. + + We don't do this with classes and enums because their attributes + are part of their definitions, not something added on. */ + + if (abi_version_at_least (9) && !OVERLOAD_TYPE_P (type)) + { + auto_vec vec; + for (tree a = TYPE_ATTRIBUTES (type); a; a = TREE_CHAIN (a)) + { + tree name = get_attribute_name (a); + const attribute_spec *as = lookup_attribute_spec (name); + if (as && as->affects_type_identity + && !is_attribute_p ("abi_tag", name)) + vec.safe_push (a); + } + vec.qsort (attr_strcmp); + while (!vec.is_empty()) + { + tree a = vec.pop(); + const attribute_spec *as + = lookup_attribute_spec (get_attribute_name (a)); + + write_char ('U'); + write_unsigned_number (strlen (as->name)); + write_string (as->name); + if (TREE_VALUE (a)) + { + write_char ('I'); + for (tree args = TREE_VALUE (a); args; + args = TREE_CHAIN (args)) + { + tree arg = TREE_VALUE (args); + write_template_arg (arg); + } + write_char ('E'); + } + + ++num_qualifiers; + } + } + + /* Note that we do not use cp_type_quals below; given "const int[3]", the "const" is emitted with the "int", not with the array. */ cp_cv_quals quals = TYPE_QUALS (type); diff --git a/gcc/testsuite/g++.dg/abi/mangle-regparm.C b/gcc/testsuite/g++.dg/abi/mangle-regparm.C new file mode 100644 index 0000000..7d4121b --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle-regparm.C @@ -0,0 +1,29 @@ +// { dg-do run { target i?86-*-* } } +// { dg-final { scan-assembler "_Z18IndirectExternCallIPU7stdcallU7regparmILi3EEFviiEiEvT_T0_S3_" } } + +typedef __SIZE_TYPE__ size_t; + +template +void IndirectExternCall(F f, T t1, T t2) { + typedef F (*WrapF)(F); + f (t1, t2); +} + +__attribute__((regparm(3), stdcall)) +void regparm_func (int i, int j) +{ + if (i != 24 || j != 42) + __builtin_abort(); +} + +void normal_func (int i, int j) +{ + if (i != 24 || j != 42) + __builtin_abort(); +} + +int main() +{ + IndirectExternCall (regparm_func, 24, 42); + IndirectExternCall (normal_func, 24, 42); +} diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index 77c2cee..2988b6b 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.c @@ -2470,6 +2470,9 @@ cplus_demangle_type (struct d_info *di) case 'U': d_advance (di, 1); ret = d_source_name (di); + if (d_peek_char (di) == 'I') + ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, + d_template_args (di)); ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL, cplus_demangle_type (di), ret); break; diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected index a030685..6ea64ae 100644 --- a/libiberty/testsuite/demangle-expected +++ b/libiberty/testsuite/demangle-expected @@ -4356,3 +4356,6 @@ _QueueNotification_QueueController__$4PPPPPPPM_A_INotice___Z --format=gnu-v3 _Z1fSsB3fooS_ f(std::string[abi:foo], std::string[abi:foo]) +--format=gnu-v3 +_Z18IndirectExternCallIPU7stdcallU7regparmILi3EEFviiEiEvT_T0_S3_ +void IndirectExternCall stdcall*)(int, int), int>(void ( regparm<3> stdcall*)(int, int), int, void ( regparm<3> stdcall*)(int, int))