PR c++/84294 - attributes on a function template redeclaration silently discarded
authorMartin Sebor <msebor@redhat.com>
Fri, 2 Mar 2018 00:16:52 +0000 (00:16 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Fri, 2 Mar 2018 00:16:52 +0000 (17:16 -0700)
gcc/cp/ChangeLog:

PR c++/84294
* decl.c (check_redeclaration_no_default_args): Merge attributes
specified on redeclarations of the same function template.
Remove dead code.

gcc/testsuite/ChangeLog:

PR c++/84294
* g++.dg/ext/attr-const.C: Remove xfail.
* g++.dg/ext/attr-malloc-3.C: New test.
* g++.dg/ext/attr-noinline-3.C: New test.
* g++.dg/ext/attr-noreturn-3.C: New test.
* g++.dg/ext/attr-nothrow-3.C: New test.
* g++.dg/ext/attr-pure.C: Remove xfail.

From-SVN: r258121

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/attr-const.C
gcc/testsuite/g++.dg/ext/attr-malloc-3.C
gcc/testsuite/g++.dg/ext/attr-noinline-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/attr-noreturn-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/attr-nothrow-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/attr-pure.C

index d44845b..2d5363c 100644 (file)
@@ -1,3 +1,10 @@
+2018-03-01  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/84294
+       * decl.c (check_redeclaration_no_default_args): Merge attributes
+       specified on redeclarations of the same function template.
+       Remove dead code.
+
 2018-03-01  Marek Polacek  <polacek@redhat.com>
            Jason Merrill  <jason@redhat.com>
 
index db64d12..735ed5d 100644 (file)
@@ -1355,6 +1355,26 @@ check_redeclaration_no_default_args (tree decl)
       }
 }
 
+/* Merge tree bits that correspond to attributes noreturn, nothrow,
+   const,  malloc, and pure from NEWDECL with those of OLDDECL.  */
+
+static void
+merge_attribute_bits (tree newdecl, tree olddecl)
+{
+  TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
+  TREE_THIS_VOLATILE (olddecl) |= TREE_THIS_VOLATILE (newdecl);
+  TREE_NOTHROW (newdecl) |= TREE_NOTHROW (olddecl);
+  TREE_NOTHROW (olddecl) |= TREE_NOTHROW (newdecl);
+  TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
+  TREE_READONLY (olddecl) |= TREE_READONLY (newdecl);
+  DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
+  DECL_IS_MALLOC (olddecl) |= DECL_IS_MALLOC (newdecl);
+  DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl);
+  DECL_PURE_P (olddecl) |= DECL_PURE_P (newdecl);
+  DECL_UNINLINABLE (newdecl) |= DECL_UNINLINABLE (olddecl);
+  DECL_UNINLINABLE (olddecl) |= DECL_UNINLINABLE (newdecl);
+}
+
 #define GNU_INLINE_P(fn) (DECL_DECLARED_INLINE_P (fn)                  \
                          && lookup_attribute ("gnu_inline",            \
                                               DECL_ATTRIBUTES (fn)))
@@ -2048,6 +2068,8 @@ next_arg:;
              DECL_DISREGARD_INLINE_LIMITS (old_result)
                |= DECL_DISREGARD_INLINE_LIMITS (new_result);
              check_redeclaration_exception_specification (newdecl, olddecl);
+
+             merge_attribute_bits (new_result, old_result);
            }
        }
 
@@ -2228,18 +2250,7 @@ next_arg:;
            |= DECL_LOOPING_CONST_OR_PURE_P (olddecl);
 
          if (merge_attr)
-           {
-             TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
-             TREE_THIS_VOLATILE (olddecl) |= TREE_THIS_VOLATILE (newdecl);
-             TREE_NOTHROW (newdecl) |= TREE_NOTHROW (olddecl);
-             TREE_NOTHROW (olddecl) |= TREE_NOTHROW (newdecl);
-             TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
-             TREE_READONLY (olddecl) |= TREE_READONLY (newdecl);
-             DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
-             DECL_IS_MALLOC (olddecl) |= DECL_IS_MALLOC (newdecl);
-             DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl);
-             DECL_PURE_P (olddecl) |= DECL_PURE_P (newdecl);
-           }
+           merge_attribute_bits (newdecl, olddecl);
          else
            {
              /* Merge the noreturn bit.  */
@@ -2412,32 +2423,15 @@ next_arg:;
 
          /* [temp.expl.spec/14] We don't inline explicit specialization
             just because the primary template says so.  */
+         gcc_assert (!merge_attr);
 
-         if (merge_attr)
-           {
-             /* But still keep DECL_DISREGARD_INLINE_LIMITS in sync with
-                the always_inline attribute.  */
-             if (DECL_DISREGARD_INLINE_LIMITS (olddecl)
-                 && !DECL_DISREGARD_INLINE_LIMITS (newdecl))
-               {
-                 if (DECL_DECLARED_INLINE_P (newdecl))
-                   DECL_DISREGARD_INLINE_LIMITS (newdecl) = true;
-                 else
-                   DECL_ATTRIBUTES (newdecl)
-                     = remove_attribute ("always_inline",
-                                         DECL_ATTRIBUTES (newdecl));
-               }
-           }
-         else
-           {
-             DECL_DECLARED_INLINE_P (olddecl)
-               = DECL_DECLARED_INLINE_P (newdecl);
+         DECL_DECLARED_INLINE_P (olddecl)
+           = DECL_DECLARED_INLINE_P (newdecl);
 
-             DECL_DISREGARD_INLINE_LIMITS (olddecl)
-               = DECL_DISREGARD_INLINE_LIMITS (newdecl);
+         DECL_DISREGARD_INLINE_LIMITS (olddecl)
+           = DECL_DISREGARD_INLINE_LIMITS (newdecl);
 
-             DECL_UNINLINABLE (olddecl) = DECL_UNINLINABLE (newdecl);
-           }
+         DECL_UNINLINABLE (olddecl) = DECL_UNINLINABLE (newdecl);
        }
       else if (new_defines_function && DECL_INITIAL (olddecl))
        {
index ef84baf..62fde2d 100644 (file)
@@ -1,3 +1,13 @@
+2018-03-01  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/84294
+       * g++.dg/ext/attr-const.C: Remove xfail.
+       * g++.dg/ext/attr-malloc-3.C: New test.
+       * g++.dg/ext/attr-noinline-3.C: New test.
+       * g++.dg/ext/attr-noreturn-3.C: New test.
+       * g++.dg/ext/attr-nothrow-3.C: New test.
+       * g++.dg/ext/attr-pure.C: Remove xfail.
+
 2018-03-02  Jakub Jelinek  <jakub@redhat.com>
 
        PR sanitizer/70875
index 28f2c6e..17cdae6 100644 (file)
@@ -68,6 +68,5 @@ void test_fnone_const ()
   if (i0 != i1)
     templ_none_const_failed ();
 
-  // The following fails (most likely) due to bug 84294.
-  // { dg-final { scan-tree-dump-not "templ_none_const_failed" "optimized" { xfail *-*-* } } }
+  // { dg-final { scan-tree-dump-not "templ_none_const_failed" "optimized" } }
 }
index e4470af..5f91ee1 100644 (file)
@@ -91,7 +91,6 @@ void test_templ_none_malloc (void)
   if (p == a)                       // must be false
     templ_none_malloc_failed ();    // should be eliminated
 
-  // The following fails (most likely) due to bug 84294.
   // Verify that the call to templ_none_malloc_failed() is eliminated.
-  // { dg-final { scan-tree-dump-not "templ_none_malloc_failed" "optimized" { xfail *-*-* } } }
+  // { dg-final { scan-tree-dump-not "templ_none_malloc_failed" "optimized" } }
 }
diff --git a/gcc/testsuite/g++.dg/ext/attr-noinline-3.C b/gcc/testsuite/g++.dg/ext/attr-noinline-3.C
new file mode 100644 (file)
index 0000000..f3f9856
--- /dev/null
@@ -0,0 +1,45 @@
+/*  PR c++/84294 - attributes on a function template redeclaration silently
+    discarded
+    { dg-do compile }
+    { dg-options "-O -fdump-tree-optimized" } */
+
+template <void test ()>
+void test_func ()
+{
+  test ();
+}
+
+int x;
+
+void __attribute__ ((noinline)) func_noinline_none ();
+void func_noinline_none () { x = __LINE__; }
+
+template void test_func<func_noinline_none>();
+// { dg-final { scan-tree-dump-times "func_noinline_none *\\(\\);" 1 "optimized" } }
+
+
+void func_none_noinline ();
+void  __attribute__ ((noinline)) func_none_noinline () { x = __LINE__; }
+
+template void test_func<func_none_noinline>();
+// { dg-final { scan-tree-dump-times "func_none_noinline *\\(\\);" 1 "optimized" } }
+
+
+template <class>
+void __attribute__ ((noinline)) templ_noinline_none () { x = __LINE__; }
+
+template <class>
+void templa_noinline_none ();
+
+template void test_func<templ_noinline_none<int> >();
+// { dg-final { scan-tree-dump-times "templ_noinline_none<int> *\\(\\);" 1 "optimized" } }
+
+
+template <class>
+void templ_none_noinline ();
+
+template <class>
+void  __attribute__ ((noinline)) templ_none_noinline () { x = __LINE__; }
+
+template void test_func<templ_none_noinline<int> >();
+// { dg-final { scan-tree-dump-times "templ_none_noinline<int> *\\(\\);" 1 "optimized" } }
diff --git a/gcc/testsuite/g++.dg/ext/attr-noreturn-3.C b/gcc/testsuite/g++.dg/ext/attr-noreturn-3.C
new file mode 100644 (file)
index 0000000..819ed32
--- /dev/null
@@ -0,0 +1,54 @@
+/*  PR c++/84294 - attributes on a function template redeclaration silently
+    discarded
+    { dg-do compile }
+    { dg-options "-O -fdump-tree-optimized" } */
+
+typedef void Func ();
+
+template <Func>
+void fail_func ();
+
+template <Func test>
+int test_func ()
+{
+  test ();
+
+  // Should be eliminated.
+  fail_func<test> ();
+
+  // Expect no -Wreturn type here despite the absence of a return
+  // statement in a non-void function.
+}   // { dg-bogus "\\\[-Wreturn-type]" "bug 84621" { xfail *-*-* } }
+
+void __attribute__ ((noreturn)) func_noreturn_none ();
+void func_noreturn_none ();
+
+template int test_func<func_noreturn_none>();
+
+
+void func_none_noreturn ();
+void  __attribute__ ((noreturn)) func_none_noreturn ();
+
+template int test_func<func_none_noreturn>();
+
+
+template <class>
+void __attribute__ ((noreturn)) templ_noreturn_none ();
+
+template <class>
+void templa_noreturn_none ();
+
+template int test_func<templ_noreturn_none<int> >();
+
+
+template <class>
+void templ_none_noreturn ();
+
+template <class>
+void  __attribute__ ((noreturn)) templ_none_noreturn ();
+
+template int test_func<templ_none_noreturn<int> >();
+
+
+// Verify that calls to fail_func() specializations have been eliminated.
+// { dg-final { scan-tree-dump-not "fail_func" "optimized" } }
diff --git a/gcc/testsuite/g++.dg/ext/attr-nothrow-3.C b/gcc/testsuite/g++.dg/ext/attr-nothrow-3.C
new file mode 100644 (file)
index 0000000..ed88826
--- /dev/null
@@ -0,0 +1,60 @@
+/*  PR c++/84294 - attributes on a function template redeclaration silently
+    discarded
+    { dg-do compile }
+    { dg-options "-O -fdump-tree-eh -fdump-tree-optimized" } */
+
+typedef void Func ();
+
+template <Func>
+void fail_func () throw ();
+
+template <Func test>
+void test_func () throw ()
+{
+  try
+    {
+      test ();
+    }
+  catch (...)
+    {
+      // Should be eliminated.
+      fail_func<test> ();
+    }
+}
+
+void __attribute__ ((nothrow)) func_nothrow_none ();
+void func_nothrow_none ();
+
+template void test_func<func_nothrow_none>();
+
+
+void func_none_nothrow ();
+void  __attribute__ ((nothrow)) func_none_nothrow ();
+
+template void test_func<func_none_nothrow>();
+
+
+template <class>
+void __attribute__ ((nothrow)) templ_nothrow_none ();
+
+template <class>
+void templa_nothrow_none ();
+
+template void test_func<templ_nothrow_none<int> >();
+
+
+template <class>
+void templ_none_nothrow ();
+
+template <class>
+void  __attribute__ ((nothrow)) templ_none_nothrow ();
+
+template void test_func<templ_none_nothrow<int> >();
+
+
+// Verify that no exception handling code was emitted.
+// { dg-final { scan-tree-dump-not "eh_dispatch" "eh" } }
+// { dg-final { scan-tree-dump-not "resx" "eh" } }
+
+// Verify that calls to fail_func() specializations have been eliminated.
+// { dg-final { scan-tree-dump-not "fail_func" "optimized" } }
index 12532cb..0f25986 100644 (file)
@@ -69,6 +69,5 @@ void test_fnone_const ()
   if (i0 != i1)
     templ_none_const_failed ();
 
-  // The following fails (most likely) due to bug 84294.
-  // { dg-final { scan-tree-dump-not "templ_none_const_failed" "optimized" { xfail *-*-* } } }
+  // { dg-final { scan-tree-dump-not "templ_none_const_failed" "optimized" } }
 }