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

2018-02-15 Thread Richard Biener
On Wed, Feb 14, 2018 at 6:10 PM, Jason Merrill  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.


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

2018-02-14 Thread Jason Merrill
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 
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 000..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() {