Commit f454bd64 by Martin Sebor Committed by Martin Sebor

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.
	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
parent b3a0e110
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>
......
......@@ -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))
{
......
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
......
......@@ -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" } }
}
/* 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" } }
/* 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" } }
/* 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" } }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment