diff mbox

[C++,RFC] Fix up attribute handling in templates (PR c++/79502)

Message ID 20170216163333.GF1849@tucnak
State New
Headers show

Commit Message

Jakub Jelinek Feb. 16, 2017, 4:33 p.m. UTC
On Thu, Feb 16, 2017 at 04:57:54PM +0100, Jakub Jelinek wrote:
> Unfortunately it broke bootstrap, *p can already contain some
> other attributes (like abi_tag) and then we ICE in
> apply_identity_attributes.  Note the attrib54.C testcase ICEs even
> on vanilla trunk, so if there are any dependent attribute, it is preexisting
> issue.
> 
> The following patch bootstrapped successfully, but I see
> +FAIL: g++.dg/ext/vector32.C  -std=c++* (internal compiler error)
> +FAIL: g++.dg/ext/vector32a.C  -std=c++* (internal compiler error)
> +FAIL: g++.dg/gomp/declare-simd-1.C  -std=gnu++* (internal compiler error)
> +FAIL: g++.dg/gomp/declare-simd-1.C  -std=gnu++* (test for excess errors)
> +FAIL: g++.dg/lto/20091219 cp_lto_20091219_0.o assemble, -O3 -flto (internal compiler error)
> +FAIL: g++.dg/vect/simd-clone-4.cc  -std=c++* (test for excess errors)
> +FAIL: g++.dg/vect/simd-clone-5.cc  -std=c++* (test for excess errors)
> on i686-linux (x86_64-linux regtest still running).  So there are further
> issues.

The issue with the above is that all those are DECL_ATTRIBUTES
which are copied over through copy_node inside of tsubst_decl or so.
Preserving the previous attributes in that case is harmful, they can
contain dependent attributes etc.
That compared to TYPE_ATTRIBUTES which start empty (at least for
classes, for enums there is that
              t = start_enum (TYPE_IDENTIFIER (template_type), NULL_TREE,
                              tsubst (ENUM_UNDERLYING_TYPE (template_type),
                                      arglist, complain, in_decl),
                              tsubst_attributes (TYPE_ATTRIBUTES (template_type),
                                                 arglist, complain, in_decl),
                              SCOPED_ENUM_P (template_type), NULL);
) and then sometimes have something added there (such as the abi_tag
attributes) before apply_late_template_attributes is called.

With the following patch I have:
make check-g++ RUNTESTFLAGS="--target_board=unix\{-m32,-m64\} dg.exp='vector*.C attrib* nodiscard*' gomp.exp=declare-simd* lto.exp=20091219* vect.exp=simd-clone-*.cc"
without any FAILs.  Not sure about the enums, wonder if the abi_tags
attributes couldn't be added even for those.

2017-02-16  Jakub Jelinek  <jakub@redhat.com>

	PR c++/79502
	* pt.c (apply_late_template_attributes): If there are
	no dependent attributes, set *p to attributes.  If there were
	some attributes in *p previously with or without dependent
	attributes, chain them after the new attributes.

	* g++.dg/cpp1z/nodiscard4.C: New test.
	* g++.dg/ext/attrib53.C: New test.
	* g++.dg/ext/attrib54.C: New test.
	* g++.dg/ext/attrib55.C: New test.



	Jakub
diff mbox

Patch

--- gcc/cp/pt.c.jj	2017-02-16 12:00:20.044455757 +0100
+++ gcc/cp/pt.c	2017-02-16 15:07:31.678727294 +0100
@@ -10086,6 +10086,7 @@  apply_late_template_attributes (tree *de
       if (TREE_TYPE (*decl_p) == error_mark_node)
 	return;
       p = &DECL_ATTRIBUTES (*decl_p);
+      *p = NULL_TREE;
     }
   else
     p = &TYPE_ATTRIBUTES (*decl_p);
@@ -10094,6 +10095,7 @@  apply_late_template_attributes (tree *de
     {
       tree late_attrs = NULL_TREE;
       tree *q = &late_attrs;
+      tree prev = *p;
 
       for (*p = attributes; *p; )
 	{
@@ -10110,9 +10112,14 @@  apply_late_template_attributes (tree *de
 	  else
 	    p = &TREE_CHAIN (t);
 	}
+      *p = prev;
 
       cplus_decl_attributes (decl_p, late_attrs, attr_flags);
     }
+  else if (*p == NULL)
+    *p = attributes;
+  else if (attributes)
+    *p = chainon (copy_list (attributes), *p);
 }
 
 /* Perform (or defer) access check for typedefs that were referenced
--- gcc/testsuite/g++.dg/cpp1z/nodiscard4.C.jj	2017-02-16 14:04:22.602748039 +0100
+++ gcc/testsuite/g++.dg/cpp1z/nodiscard4.C	2017-02-16 14:04:22.601748053 +0100
@@ -0,0 +1,14 @@ 
+// PR c++/79502
+// { dg-do compile { target c++11 } }
+
+template<typename>
+struct [[nodiscard]] missiles {};
+
+missiles<void> make() { return {}; }
+missiles<void> (*fnptr)() = make;
+
+int main()
+{
+  make();	// { dg-warning "ignoring returned value of type" }
+  fnptr();	// { dg-warning "ignoring returned value of type" }
+}
--- gcc/testsuite/g++.dg/ext/attrib53.C.jj	2017-02-16 15:08:18.635107840 +0100
+++ gcc/testsuite/g++.dg/ext/attrib53.C	2017-02-16 15:09:50.210899761 +0100
@@ -0,0 +1,21 @@ 
+// { dg-do compile { target c++11 } }
+
+inline namespace N __attribute__((__abi_tag__ ("foo"))) {}
+template <typename> struct A;
+namespace N {
+template <typename> class B;
+}
+template <typename> class C {};
+template <typename> struct D {
+  template <typename _Up> using G = C<_Up>;
+};
+template <typename T> struct F {
+  template <typename U> struct H {
+    typedef typename D<T>::template G<U> I;
+  };
+};
+template <typename T, typename = C<T>> struct J {
+  C<A<const B<char>>> L;
+  typedef F<C<int>>::H<A<const B<char>>>::I M;
+  J<M> *a;
+};
--- gcc/testsuite/g++.dg/cpp0x/attrib54.C.jj	2017-02-16 15:08:21.739066892 +0100
+++ gcc/testsuite/g++.dg/cpp0x/attrib54.C	2017-02-16 15:10:02.461738146 +0100
@@ -0,0 +1,21 @@ 
+// { dg-do compile { target c++11 } }
+
+inline namespace N __attribute__((__abi_tag__ ("foo"))) {}
+template <typename> struct A {};
+namespace N {
+template <typename> class B {};
+}
+template <typename T> class __attribute__((__aligned__ (sizeof (T)))) C {};
+template <typename> struct D {
+  template <typename _Up> using G = C<_Up>;
+};
+template <typename T> struct F {
+  template <typename U> struct H {
+    typedef typename D<T>::template G<U> I;
+  };
+};
+template <typename T, typename = C<T>> struct J {
+  C<A<const B<char>>> L;
+  typedef F<C<int>>::H<A<const B<char>>>::I M;
+  J<M> *a;
+};
--- gcc/testsuite/g++.dg/cpp0x/attrib55.C.jj	2017-02-16 15:08:26.801000114 +0100
+++ gcc/testsuite/g++.dg/cpp0x/attrib55.C	2017-02-16 15:10:11.422619933 +0100
@@ -0,0 +1,21 @@ 
+// { dg-do compile { target c++11 } }
+
+inline namespace N __attribute__((__abi_tag__ ("foo"))) {}
+template <typename> struct A {};
+namespace N {
+template <typename> class B {};
+}
+template <typename T> class __attribute__((__unused__)) C {};
+template <typename> struct D {
+  template <typename _Up> using G = C<_Up>;
+};
+template <typename T> struct F {
+  template <typename U> struct H {
+    typedef typename D<T>::template G<U> I;
+  };
+};
+template <typename T, typename = C<T>> struct J {
+  C<A<const B<char>>> L;
+  typedef F<C<int>>::H<A<const B<char>>>::I M;
+  J<M> *a;
+};