RFA: PATCH to build_type_attribute_qual_variant for c++/84314, ICE with fastcall

Message ID CADzB+2=SZUvL0F6AD+2LsbBh3CA_s8xdof4zquu2ABmwjoWYGQ@mail.gmail.com
State New
Headers show
Series
  • RFA: PATCH to build_type_attribute_qual_variant for c++/84314, ICE with fastcall
Related show

Commit Message

Jason Merrill Feb. 14, 2018, 5:10 p.m.
This testcase involves a fastcall-qualified function type.  During
mangling, we use build_type_attribute_qual_variant to look up an
attribute-unqualified version of that type.
build_type_attribute_qual_variant calls type_hash_canon and finds the
original unqualified type, but then clobbers its TYPE_CANONICAL
because it's incompatible with the fastcall-qualified type.

Fixed by leaving TYPE_CANONICAL of a previously existing type alone.

Tested x86_64-pc-linux-gnu.  OK for trunk?
commit dca04c7fb9d7002d342f6e5d47dfbe85569dbc5e
Author: Jason Merrill <jason@redhat.com>
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.

Comments

Richard Biener Feb. 15, 2018, 3:02 p.m. | #1
On Wed, Feb 14, 2018 at 6:10 PM, Jason Merrill <jason@redhat.com> wrote:
> This testcase involves a fastcall-qualified function type.  During

> mangling, we use build_type_attribute_qual_variant to look up an

> attribute-unqualified version of that type.

> build_type_attribute_qual_variant calls type_hash_canon and finds the

> original unqualified type, but then clobbers its TYPE_CANONICAL

> because it's incompatible with the fastcall-qualified type.

>

> Fixed by leaving TYPE_CANONICAL of a previously existing type alone.

>

> Tested x86_64-pc-linux-gnu.  OK for trunk?


Ok.

Patch

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 <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);
+}