aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2017-02-16 20:49:19 +0100
committerJason Merrill <jason@gcc.gnu.org>2017-02-16 14:49:19 -0500
commit790ecf853295e25cdd3f92113bc9dca1cf143040 (patch)
tree46815e5e2d7e39820e47d6fbf4a625d01bb9f081
parentdbd0ef6d89f370c51b29f22b8da07ad446192eee (diff)
downloadgcc-790ecf853295e25cdd3f92113bc9dca1cf143040.zip
gcc-790ecf853295e25cdd3f92113bc9dca1cf143040.tar.gz
gcc-790ecf853295e25cdd3f92113bc9dca1cf143040.tar.bz2
PR c++/79502 - lost nodiscard attribute
* pt.c (apply_late_template_attributes): Do apply non-dependent attributes to types. Co-Authored-By: Jason Merrill <jason@redhat.com> From-SVN: r245516
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/pt.c32
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/attrib54.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/attrib55.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/nodiscard4.C14
-rw-r--r--gcc/testsuite/g++.dg/ext/attrib53.C21
6 files changed, 107 insertions, 9 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 66c491e..11ef320 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 712fb69..73d6be3 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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
index 0000000..e5817c3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/attrib54.C
@@ -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
index 0000000..79d0c8c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/attrib55.C
@@ -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
index 0000000..8a95c94
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/nodiscard4.C
@@ -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
index 0000000..408433d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attrib53.C
@@ -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;
+};