diff options
author | Jason Merrill <jason@redhat.com> | 2018-02-15 11:54:12 -0500 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2018-02-15 11:54:12 -0500 |
commit | 5cedffbc3249a3f14ea57567a5f089d502cad8d3 (patch) | |
tree | 1478e723a54aba8f641e33069ff42a56ef1984c1 | |
parent | e72f7e3e763c1091c0007a851f252f13310f6255 (diff) | |
download | gcc-5cedffbc3249a3f14ea57567a5f089d502cad8d3.zip gcc-5cedffbc3249a3f14ea57567a5f089d502cad8d3.tar.gz gcc-5cedffbc3249a3f14ea57567a5f089d502cad8d3.tar.bz2 |
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.
From-SVN: r257695
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/attribs.c | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/attrib55.C | 99 |
3 files changed, 122 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3537bd4..4062532 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2018-02-15 Jason Merrill <jason@redhat.com> + + 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. + 2018-02-15 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/84383 diff --git a/gcc/attribs.c b/gcc/attribs.c index 140863b..caa30b9 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -1143,19 +1143,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 0000000..dc0cdc4 --- /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 <typename a, a b> struct c { static constexpr a d = b; }; +template <bool b> using e = c<bool, b>; +template <bool, typename, typename> struct conditional; +template <typename...> struct f; +template <typename g, typename h> +struct f<g, h> : conditional<g::d, g, h>::i {}; +template <typename...> struct j; +template <typename g, typename h> struct j<g, h> : conditional<1, h, g>::i {}; +template <typename g, typename h, typename k, typename... l> +struct j<g, h, k, l...> : conditional<1, j<h, k>, g>::i {}; +struct aa : e<!bool()> {}; +template <typename, typename> struct m : c<bool, false> {}; +template <typename, typename n> struct o { + template <typename> static c<bool, true> p(int); + typedef decltype(p<n>(0)) i; +}; +template <typename, typename> struct ab : o<int, int>::i {}; +template <typename> struct s { typedef int ad; }; +template <bool, typename = void> struct q; +template <typename a> struct q<true, a> { typedef a i; }; +template <bool, typename ae, typename> struct conditional { typedef ae i; }; +template <typename ae, typename r> struct conditional<false, ae, r> { + typedef r i; +}; +struct B { + B(int); +}; +template <unsigned, typename...> struct af; +template <unsigned ag, typename t, typename... ah> +struct af<ag, t, ah...> : af<1, ah...>, B { + typedef af<1, ah...> ai; + ai al(af); + template <typename... am> af(af<ag, am...> p1) : ai(al(p1)), B(0) {} +}; +template <unsigned ag, typename t> struct af<ag, t> {}; +template <int, typename... ao> struct ap { + template <typename... am> static constexpr bool ar() { + return j<ab<am, ao>...>::d; + } +}; +template <typename... ao> class as : public af<0, ao...> { + typedef af<0, ao...> ai; + +public: + template <typename...> using au = ap<m<int, int>::d, ao...>; + template <typename... am, + typename q<au<>::template ar<am...>(), bool>::i = true> + as(as<am...> an) : ai(an) {} +}; +template <typename... ao> as<typename s<ao>::ad...> ax(ao...); +namespace ay { +class az {}; +} +using ay::az; +namespace ay { +template <typename ba> struct C { typedef ba bc; }; +} +template <typename> class bd; +template <typename bi, typename n> using bj = f<m<bi, n>, ab<bi, n>>; +template <typename bf, typename... bh> class bd<bf(bh...)> { + struct F : bj<int, bf> {}; + template <typename bl, typename> using bm = typename q<bl::d>::i; + +public: + template <typename bg, typename = bm<aa, void>, typename = bm<F, void>> + bd(bg); + using bn = bf; + bn bo; +}; +template <typename bf, typename... bh> +template <typename bg, typename, typename> +bd<bf(bh...)>::bd(bg) { + bo; +} +typedef long long(__attribute__((fastcall)) bq)(int *); +struct v : ay::C<as<bq, bq, int>> { + 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<long long(int *)>); +}; +} +void x::ce() { + auto bu = 0; + u::cf::cg(bu, cc(), 1, {}, 0); +} |