PR c++/84294 - attributes on a function template redeclaration silently discarded
gcc/cp/ChangeLog:
PR c++/84294
* decl.c (check_redeclaration_no_default_args): Merge attributes
specified on redeclarations of the same function template.
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.
===================================================================
@@ -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. */
===================================================================
@@ -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" } }
}
===================================================================
@@ -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" } }
}
===================================================================
@@ -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" } }
===================================================================
@@ -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" } }
===================================================================
@@ -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" } }
===================================================================
@@ -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" } }
}