commit dca04c7fb9d7002d342f6e5d47dfbe85569dbc5e Author: Jason Merrill Date: Tue Feb 13 15:15:26 2018 -0500 PR c++/84314 - ICE with templates and fastcall attribute. * attribs.c (build_type_attribute_qual_variant): Don't clobber TYPE_CANONICAL on an existing type. diff --git a/gcc/attribs.c b/gcc/attribs.c index 2cac9c403b4..d13a3d4b88b 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -1127,19 +1127,29 @@ build_type_attribute_qual_variant (tree otype, tree attribute, int quals) ttype = (lang_hooks.types.copy_lang_qualifiers (ttype, TYPE_MAIN_VARIANT (otype))); - ntype = build_distinct_type_copy (ttype); + tree dtype = ntype = build_distinct_type_copy (ttype); TYPE_ATTRIBUTES (ntype) = attribute; hashval_t hash = type_hash_canon_hash (ntype); ntype = type_hash_canon (hash, ntype); - /* If the target-dependent attributes make NTYPE different from - its canonical type, we will need to use structural equality - checks for this type. */ - if (TYPE_STRUCTURAL_EQUALITY_P (ttype) - || !comp_type_attributes (ntype, ttype)) - SET_TYPE_STRUCTURAL_EQUALITY (ntype); + if (ntype != dtype) + /* This variant was already in the hash table, don't mess with + TYPE_CANONICAL. */; + else if (TYPE_STRUCTURAL_EQUALITY_P (ttype) + || !comp_type_attributes (ntype, ttype)) + { + /* If the target-dependent attributes make NTYPE different from + its canonical type, we will need to use structural equality + checks for this type. + + But make sure we don't get here for stripping attributes from a + type; the no-attribute type might not need structural comparison, + and it should have been in the hash table already. */ + gcc_assert (attribute); + SET_TYPE_STRUCTURAL_EQUALITY (ntype); + } else if (TYPE_CANONICAL (ntype) == ntype) TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype); diff --git a/gcc/testsuite/g++.dg/ext/attrib55.C b/gcc/testsuite/g++.dg/ext/attrib55.C new file mode 100644 index 00000000000..dc0cdc48b7a --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attrib55.C @@ -0,0 +1,99 @@ +// PR c++/84314 +// { dg-do compile { target { { i?86-*-* x86_64-*-* } && ia32 } } } +// { dg-additional-options "-w -std=c++11" } + +template struct c { static constexpr a d = b; }; +template using e = c; +template struct conditional; +template struct f; +template +struct f : conditional::i {}; +template struct j; +template struct j : conditional<1, h, g>::i {}; +template +struct j : conditional<1, j, g>::i {}; +struct aa : e {}; +template struct m : c {}; +template struct o { + template static c p(int); + typedef decltype(p(0)) i; +}; +template struct ab : o::i {}; +template struct s { typedef int ad; }; +template struct q; +template struct q { typedef a i; }; +template struct conditional { typedef ae i; }; +template struct conditional { + typedef r i; +}; +struct B { + B(int); +}; +template struct af; +template +struct af : af<1, ah...>, B { + typedef af<1, ah...> ai; + ai al(af); + template af(af p1) : ai(al(p1)), B(0) {} +}; +template struct af {}; +template struct ap { + template static constexpr bool ar() { + return j...>::d; + } +}; +template class as : public af<0, ao...> { + typedef af<0, ao...> ai; + +public: + template using au = ap::d, ao...>; + template ::template ar(), bool>::i = true> + as(as an) : ai(an) {} +}; +template as::ad...> ax(ao...); +namespace ay { +class az {}; +} +using ay::az; +namespace ay { +template struct C { typedef ba bc; }; +} +template class bd; +template using bj = f, ab>; +template class bd { + struct F : bj {}; + template using bm = typename q::i; + +public: + template , typename = bm> + bd(bg); + using bn = bf; + bn bo; +}; +template +template +bd::bd(bg) { + bo; +} +typedef long long(__attribute__((fastcall)) bq)(int *); +struct v : ay::C> { + bc bt() { return ax(nullptr, nullptr, az()); } +}; +class w { +public: + int *cc(); +}; +class x : w { + void ce(); +}; +namespace u { +class cf { +public: + static cf cg(int, int *, int, az, bd); +}; +} +void x::ce() { + auto bu = 0; + u::cf::cg(bu, cc(), 1, {}, 0); +}