PR c++/79502 - lost nodiscard attribute
authorJakub Jelinek <jakub@redhat.com>
Thu, 16 Feb 2017 19:49:19 +0000 (20:49 +0100)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 16 Feb 2017 19:49:19 +0000 (14:49 -0500)
* pt.c (apply_late_template_attributes): Do apply non-dependent
attributes to types.

Co-Authored-By: Jason Merrill <jason@redhat.com>
From-SVN: r245516

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp0x/attrib54.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/attrib55.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/nodiscard4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/attrib53.C [new file with mode: 0644]

index 66c491e1bf86b71f35962f05d55c96e56ce7961c..11ef3209519a72ffae72d18a5ac7d3e5b47dbc78 100644 (file)
@@ -1,3 +1,10 @@
+2017-02-16  Jakub Jelinek  <jakub@redhat.com>
+           Jason Merrill  <jason@redhat.com>
+
+       PR c++/79502 - lost nodiscard attribute
+       * pt.c (apply_late_template_attributes): Do apply non-dependent
+       attributes to types.
+
 2017-02-16  Jason Merrill  <jason@redhat.com>
 
        PR c++/78572 - ICE with self-modifying array initializer
index 712fb6919031ba43cb72c8c3c91e417e94e4e0e2..73d6be3598ff6f32a462ebdb927863b58bbef583 100644 (file)
@@ -10073,29 +10073,43 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags,
   tree t;
   tree *p;
 
-  for (t = attributes; t; t = TREE_CHAIN (t))
-    if (ATTR_IS_DEPENDENT (t))
-      {
-       last_dep = t;
-       attributes = copy_list (attributes);
-       break;
-      }
+  if (attributes == NULL_TREE)
+    return;
 
   if (DECL_P (*decl_p))
     {
       if (TREE_TYPE (*decl_p) == error_mark_node)
        return;
       p = &DECL_ATTRIBUTES (*decl_p);
+      /* DECL_ATTRIBUTES comes from copy_node in tsubst_decl, and is identical
+         to our attributes parameter.  */
+      gcc_assert (*p == attributes);
     }
   else
-    p = &TYPE_ATTRIBUTES (*decl_p);
+    {
+      p = &TYPE_ATTRIBUTES (*decl_p);
+      /* TYPE_ATTRIBUTES was set up (with abi_tag and may_alias) in
+        lookup_template_class_1, and should be preserved.  */
+      gcc_assert (*p != attributes);
+      while (*p)
+       p = &TREE_CHAIN (*p);
+    }
+
+  for (t = attributes; t; t = TREE_CHAIN (t))
+    if (ATTR_IS_DEPENDENT (t))
+      {
+       last_dep = t;
+       attributes = copy_list (attributes);
+       break;
+      }
 
+  *p = attributes;
   if (last_dep)
     {
       tree late_attrs = NULL_TREE;
       tree *q = &late_attrs;
 
-      for (*p = attributes; *p; )
+      for (; *p; )
        {
          t = *p;
          if (ATTR_IS_DEPENDENT (t))
diff --git a/gcc/testsuite/g++.dg/cpp0x/attrib54.C b/gcc/testsuite/g++.dg/cpp0x/attrib54.C
new file mode 100644 (file)
index 0000000..e5817c3
--- /dev/null
@@ -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;
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/attrib55.C b/gcc/testsuite/g++.dg/cpp0x/attrib55.C
new file mode 100644 (file)
index 0000000..79d0c8c
--- /dev/null
@@ -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;
+};
diff --git a/gcc/testsuite/g++.dg/cpp1z/nodiscard4.C b/gcc/testsuite/g++.dg/cpp1z/nodiscard4.C
new file mode 100644 (file)
index 0000000..8a95c94
--- /dev/null
@@ -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" }
+}
diff --git a/gcc/testsuite/g++.dg/ext/attrib53.C b/gcc/testsuite/g++.dg/ext/attrib53.C
new file mode 100644 (file)
index 0000000..408433d
--- /dev/null
@@ -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;
+};