PR c++/83871 - wrong code for attribute const and pure on distinct template specializations

PR c++/83871 - wrong code for attribute const and pure on distinct template specializations
PR c++/83503 - [8 Regression] bogus -Wattributes for const and pure on function template specialization

gcc/ChangeLog:

	PR c++/83871
	* gcc/doc/invoke.texi (-Wmissing-attributes): New option.
	* gcc/print-tree.c (print_node): Handle DECL_UNINLINABLE.

gcc/c-family/ChangeLog:

	PR c++/83871
	* c.opt (-Wmissing-attributes): New option.

gcc/cp/ChangeLog:

	PR c++/83871
	PR c++/83503
	* cp-tree.h (warn_spec_missing_attributes): New function.
	((check_explicit_specialization): Add an argument.  Call the above
	function.
	* decl.c (duplicate_decls): Avoid applying primary function template's
	attributes to its explicit specializations.
	cp/pt.c (warn_spec_missing_attributes): Define.

gcc/testsuite/ChangeLog:

	PR c++/83871
	PR c++/83503
	* g++.dg/Wmissing-attributes.C: New test.
	* g++.dg/ext/attr-const-pure.C: New test.
	* g++.dg/ext/attr-const.C: New test.
	* g++.dg/ext/attr-deprecated-2.C: New test.
	* g++.dg/ext/attr-malloc-2.C: New test.
	* g++.dg/ext/attr-malloc.C: New test.
	* g++.dg/ext/attr-noinline-2.C: New test.
	* g++.dg/ext/attr-noinline.C: New test.
	* g++.dg/ext/attr-nonnull.C: New test.
	* g++.dg/ext/attr-noreturn-2.C: New test.
	* g++.dg/ext/attr-noreturn.C: New test.
	* g++.dg/ext/attr-nothrow-2.C: New test.
	* g++.dg/ext/attr-nothrow.C: New test.
	* g++.dg/ext/attr-optimize.C: New test.
	* g++.dg/ext/attr-pure.C: New test.
	* g++.dg/ext/attr-returns-nonnull.C: New test.
	* g++.dg/ext/attr-warning.C: New test.

From-SVN: r258045
This commit is contained in:
Martin Sebor 2018-02-27 22:28:21 +00:00 committed by Martin Sebor
parent 1c89478aef
commit d4cfd486eb
27 changed files with 1404 additions and 38 deletions

View file

@ -1,3 +1,9 @@
2018-02-27 Martin Sebor <msebor@redhat.com>
PR c++/83871
* gcc/doc/invoke.texi (-Wmissing-attributes): New option.
* gcc/print-tree.c (print_node): Handle DECL_UNINLINABLE.
2018-02-27 Martin Sebor <msebor@redhat.com>
PR translation/84207

View file

@ -1,3 +1,8 @@
2018-02-27 Martin Sebor <msebor@redhat.com>
PR c++/83871
* c.opt (-Wmissing-attributes): New option.
2018-02-21 Martin Liska <mliska@suse.cz>
* c.opt (Wcatch-value=): Add IntegerRange.

View file

@ -781,6 +781,11 @@ Wtemplates
C++ ObjC++ Var(warn_templates) Warning
Warn on primary template declaration.
Wmissing-attributes
C ObjC C++ ObjC++ Var(warn_missing_attributes) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
Warn about declarations of entities that may be missing attributes
that related entities have been declared with it.
Wmissing-format-attribute
C ObjC C++ ObjC++ Warning Alias(Wsuggest-attribute=format)
;

View file

@ -1,3 +1,14 @@
2018-02-27 Martin Sebor <msebor@redhat.com>
PR c++/83871
PR c++/83503
* cp-tree.h (warn_spec_missing_attributes): New function.
((check_explicit_specialization): Add an argument. Call the above
function.
* decl.c (duplicate_decls): Avoid applying primary function template's
attributes to its explicit specializations.
cp/pt.c (warn_spec_missing_attributes): Define.
2018-02-27 Håkon Sandsmark <hsandsmark@gmail.com>
PR c++/71546 - lambda init-capture with qualified-id.

View file

@ -6463,7 +6463,8 @@ extern void end_specialization (void);
extern void begin_explicit_instantiation (void);
extern void end_explicit_instantiation (void);
extern void check_unqualified_spec_or_inst (tree, location_t);
extern tree check_explicit_specialization (tree, tree, int, int);
extern tree check_explicit_specialization (tree, tree, int, int,
tree = NULL_TREE);
extern int num_template_headers_for_class (tree);
extern void check_template_variable (tree);
extern tree make_auto (void);

View file

@ -1405,9 +1405,18 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
" literal operator template %qD", newdecl, olddecl);
}
/* True to merge attributes between the declarations, false to
set OLDDECL's attributes to those of NEWDECL (for template
explicit specializations that specify their own attributes
independent of those specified for the primary template). */
const bool merge_attr = (TREE_CODE (newdecl) != FUNCTION_DECL
|| !DECL_TEMPLATE_SPECIALIZATION (newdecl)
|| DECL_TEMPLATE_SPECIALIZATION (olddecl));
if (DECL_P (olddecl)
&& TREE_CODE (newdecl) == FUNCTION_DECL
&& TREE_CODE (olddecl) == FUNCTION_DECL
&& merge_attr
&& diagnose_mismatched_attributes (olddecl, newdecl))
{
if (DECL_INITIAL (olddecl))
@ -1969,10 +1978,13 @@ next_arg:;
DECL_ORIGINAL_TYPE (newdecl) = DECL_ORIGINAL_TYPE (olddecl);
}
/* Copy all the DECL_... slots specified in the new decl
except for any that we copy here from the old type. */
DECL_ATTRIBUTES (newdecl)
= (*targetm.merge_decl_attributes) (olddecl, newdecl);
/* Copy all the DECL_... slots specified in the new decl except for
any that we copy here from the old type. */
if (merge_attr)
DECL_ATTRIBUTES (newdecl)
= (*targetm.merge_decl_attributes) (olddecl, newdecl);
else
DECL_ATTRIBUTES (olddecl) = DECL_ATTRIBUTES (newdecl);
if (DECL_DECLARES_FUNCTION_P (olddecl) && DECL_DECLARES_FUNCTION_P (newdecl))
{
@ -2099,9 +2111,10 @@ next_arg:;
}
}
}
else
/* Merge the data types specified in the two decls. */
else if (merge_attr)
newtype = merge_types (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
else
newtype = TREE_TYPE (newdecl);
if (VAR_P (newdecl))
{
@ -2165,14 +2178,6 @@ next_arg:;
&& !(processing_template_decl && uses_template_parms (newdecl)))
layout_decl (newdecl, 0);
/* Merge the type qualifiers. */
if (TREE_READONLY (newdecl))
TREE_READONLY (olddecl) = 1;
if (TREE_THIS_VOLATILE (newdecl))
TREE_THIS_VOLATILE (olddecl) = 1;
if (TREE_NOTHROW (newdecl))
TREE_NOTHROW (olddecl) = 1;
/* Merge deprecatedness. */
if (TREE_DEPRECATED (newdecl))
TREE_DEPRECATED (olddecl) = 1;
@ -2190,6 +2195,15 @@ next_arg:;
DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl)
= DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl);
}
else
{
/* Merge the const type qualifier. */
if (TREE_READONLY (newdecl))
TREE_READONLY (olddecl) = 1;
/* Merge the volatile type qualifier. */
if (TREE_THIS_VOLATILE (newdecl))
TREE_THIS_VOLATILE (olddecl) = 1;
}
/* Merge the initialization information. */
if (DECL_INITIAL (newdecl) == NULL_TREE
@ -2209,14 +2223,29 @@ next_arg:;
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
|= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
TREE_NOTHROW (newdecl) |= TREE_NOTHROW (olddecl);
DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl);
DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl);
TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
DECL_LOOPING_CONST_OR_PURE_P (newdecl)
DECL_LOOPING_CONST_OR_PURE_P (newdecl)
|= 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);
DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl);
}
else
{
/* Merge the noreturn bit. */
TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl);
TREE_READONLY (olddecl) = TREE_READONLY (newdecl);
TREE_NOTHROW (olddecl) = TREE_NOTHROW (newdecl);
DECL_IS_MALLOC (olddecl) = DECL_IS_MALLOC (newdecl);
DECL_PURE_P (olddecl) = DECL_PURE_P (newdecl);
}
/* Keep the old RTL. */
COPY_DECL_RTL (olddecl, newdecl);
}
@ -2381,17 +2410,30 @@ next_arg:;
/* [temp.expl.spec/14] We don't inline explicit specialization
just because the primary template says so. */
/* 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 (merge_attr)
{
if (DECL_DECLARED_INLINE_P (newdecl))
DECL_DISREGARD_INLINE_LIMITS (newdecl) = true;
else
DECL_ATTRIBUTES (newdecl)
= remove_attribute ("always_inline",
DECL_ATTRIBUTES (newdecl));
/* 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_DISREGARD_INLINE_LIMITS (olddecl)
= DECL_DISREGARD_INLINE_LIMITS (newdecl);
DECL_UNINLINABLE (olddecl) = DECL_UNINLINABLE (newdecl);
}
}
else if (new_defines_function && DECL_INITIAL (olddecl))
@ -8917,7 +8959,8 @@ grokfndecl (tree ctype,
template_count,
2 * funcdef_flag +
4 * (friendp != 0) +
8 * concept_p);
8 * concept_p,
*attrlist);
if (decl == error_mark_node)
return NULL_TREE;

View file

@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
all methods must be provided in header files; can't use a source
file that contains only the method templates and "just win". */
#include <string>
#include "config.h"
#include "system.h"
#include "coretypes.h"
@ -1473,8 +1474,10 @@ is_specialization_of_friend (tree decl, tree friend_decl)
/* Register the specialization SPEC as a specialization of TMPL with
the indicated ARGS. IS_FRIEND indicates whether the specialization
is actually just a friend declaration. Returns SPEC, or an
equivalent prior declaration, if available.
is actually just a friend declaration. ATTRLIST is the list of
attributes that the specialization is declared with or NULL when
it isn't. Returns SPEC, or an equivalent prior declaration, if
available.
We also store instantiations of field packs in the hash table, even
though they are not themselves templates, to make lookup easier. */
@ -2615,6 +2618,110 @@ check_unqualified_spec_or_inst (tree t, location_t loc)
}
}
/* Warn for a template specialization SPEC that is missing some of a set
of function or type attributes that the template TEMPL is declared with.
ATTRLIST is a list of additional attributes that SPEC should be taken
to ultimately be declared with. */
static void
warn_spec_missing_attributes (tree tmpl, tree spec, tree attrlist)
{
if (DECL_FUNCTION_TEMPLATE_P (tmpl))
tmpl = DECL_TEMPLATE_RESULT (tmpl);
if (TREE_CODE (tmpl) != FUNCTION_DECL)
return;
/* Avoid warning if either declaration or its type is deprecated. */
if (TREE_DEPRECATED (tmpl)
|| TREE_DEPRECATED (spec))
return;
tree tmpl_type = TREE_TYPE (tmpl);
tree spec_type = TREE_TYPE (spec);
if (TREE_DEPRECATED (tmpl_type)
|| TREE_DEPRECATED (spec_type)
|| TREE_DEPRECATED (TREE_TYPE (tmpl_type))
|| TREE_DEPRECATED (TREE_TYPE (spec_type)))
return;
tree tmpl_attrs[] = { DECL_ATTRIBUTES (tmpl), TYPE_ATTRIBUTES (tmpl_type) };
tree spec_attrs[] = { DECL_ATTRIBUTES (spec), TYPE_ATTRIBUTES (spec_type) };
if (!spec_attrs[0])
spec_attrs[0] = attrlist;
else if (!spec_attrs[1])
spec_attrs[1] = attrlist;
/* Avoid warning if the primary has no attributes. */
if (!tmpl_attrs[0] && !tmpl_attrs[1])
return;
/* Avoid warning if either declaration contains an attribute on
the white list below. */
const char* const whitelist[] = {
"error", "warning"
};
for (unsigned i = 0; i != 2; ++i)
for (unsigned j = 0; j != sizeof whitelist / sizeof *whitelist; ++j)
if (lookup_attribute (whitelist[j], tmpl_attrs[i])
|| lookup_attribute (whitelist[j], spec_attrs[i]))
return;
/* Avoid warning if the difference between the primary and
the specialization is not in one of the attributes below. */
const char* const blacklist[] = {
"alloc_align", "alloc_size", "assume_aligned", "format",
"format_arg", "malloc", "nonnull"
};
/* Put together a list of the black listed attributes that the primary
template is declared with that the specialization is not, in case
it's not apparent from the most recent declaration of the primary. */
unsigned nattrs = 0;
std::string str;
for (unsigned i = 0; i != sizeof blacklist / sizeof *blacklist; ++i)
{
for (unsigned j = 0; j != 2; ++j)
{
if (!lookup_attribute (blacklist[i], tmpl_attrs[j]))
continue;
for (unsigned k = 0; k != 1 + !!spec_attrs[1]; ++k)
{
if (lookup_attribute (blacklist[i], spec_attrs[k]))
break;
if (str.size ())
str += ", ";
str += "%<";
str += blacklist[i];
str += "%>";
++nattrs;
}
}
}
if (!nattrs)
return;
if (warning_at (DECL_SOURCE_LOCATION (spec), OPT_Wmissing_attributes,
"explicit specialization %q#D may be missing attributes",
spec))
{
if (nattrs > 1)
str = G_("missing primary template attributes ") + str;
else
str = G_("missing primary template attribute ") + str;
inform (DECL_SOURCE_LOCATION (tmpl), str.c_str ());
}
}
/* Check to see if the function just declared, as indicated in
DECLARATOR, and in DECL, is a specialization of a function
template. We may also discover that the declaration is an explicit
@ -2656,7 +2763,8 @@ tree
check_explicit_specialization (tree declarator,
tree decl,
int template_count,
int flags)
int flags,
tree attrlist)
{
int have_def = flags & 2;
int is_friend = flags & 4;
@ -3113,8 +3221,13 @@ check_explicit_specialization (tree declarator,
it again. Partial specializations will be registered in
process_partial_specialization. */
if (!processing_template_decl)
decl = register_specialization (decl, gen_tmpl, targs,
is_friend, 0);
{
warn_spec_missing_attributes (gen_tmpl, decl, attrlist);
decl = register_specialization (decl, gen_tmpl, targs,
is_friend, 0);
}
/* A 'structor should already have clones. */
gcc_assert (decl == error_mark_node

View file

@ -295,7 +295,7 @@ Objective-C and Objective-C++ Dialects}.
-Winvalid-pch -Wlarger-than=@var{len} @gol
-Wlogical-op -Wlogical-not-parentheses -Wlong-long @gol
-Wmain -Wmaybe-uninitialized -Wmemset-elt-size -Wmemset-transposed-args @gol
-Wmisleading-indentation -Wmissing-braces @gol
-Wmisleading-indentation -Wmissing-attributes -Wmissing-braces @gol
-Wmissing-field-initializers -Wmissing-include-dirs @gol
-Wno-multichar -Wmultistatement-macros -Wnonnull -Wnonnull-compare @gol
-Wnormalized=@r{[}none@r{|}id@r{|}nfc@r{|}nfkc@r{]} @gol
@ -3928,6 +3928,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect Options}.
-Wmemset-elt-size @gol
-Wmemset-transposed-args @gol
-Wmisleading-indentation @r{(only for C/C++)} @gol
-Wmissing-attributes @gol
-Wmissing-braces @r{(only for C/ObjC)} @gol
-Wmultistatement-macros @gol
-Wnarrowing @r{(only for C++)} @gol
@ -4591,6 +4592,36 @@ about the layout of the file that the directive references.
This warning is enabled by @option{-Wall} in C and C++.
@item -Wmissing-attributes
@opindex Wmissing-attributes
@opindex Wno-missing-attributes
Warn when a declaration of a function is missing one or more attributes
that a related function is declared with and whose absence may adversely
affect the correctness or efficiency of generated code. For example, in
C++, the warning is issued when an explicit specialization of a primary
template declared with attribute @code{alloc_align}, @code{alloc_size},
@code{assume_aligned}, @code{format}, @code{format_arg}, @code{malloc},
or @code{nonnull} is declared without it. Attributes @code{deprecated},
@code{error}, and @code{warning} suppress the warning.
(@pxref{Function Attributes}).
@option{-Wmissing-attributes} is enabled by @option{-Wall}.
For example, since the declaration of the primary function template
below makes use of both attribute @code{malloc} and @code{alloc_size}
the declaration of the explicit specialization of the template is
diagnosed because it is missing one of the attributes.
@smallexample
template <class T>
T* __attribute__ ((malloc, alloc_size (1)))
allocate (size_t);
template <>
void* __attribute__ ((malloc)) // missing alloc_size
allocate<void> (size_t);
@end smallexample
@item -Wmissing-braces
@opindex Wmissing-braces
@opindex Wno-missing-braces

View file

@ -377,6 +377,8 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
fputs (" function-specific-opt", file);
if (code == FUNCTION_DECL && DECL_DECLARED_INLINE_P (node))
fputs (" autoinline", file);
if (code == FUNCTION_DECL && DECL_UNINLINABLE (node))
fputs (" uninlinable", file);
if (code == FUNCTION_DECL && DECL_BUILT_IN (node))
fputs (" built-in", file);
if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (node))

View file

@ -1,3 +1,25 @@
2018-02-27 Martin Sebor <msebor@redhat.com>
PR c++/83871
PR c++/83503
* g++.dg/Wmissing-attributes.C: New test.
* g++.dg/ext/attr-const-pure.C: New test.
* g++.dg/ext/attr-const.C: New test.
* g++.dg/ext/attr-deprecated-2.C: New test.
* g++.dg/ext/attr-malloc-2.C: New test.
* g++.dg/ext/attr-malloc.C: New test.
* g++.dg/ext/attr-noinline-2.C: New test.
* g++.dg/ext/attr-noinline.C: New test.
* g++.dg/ext/attr-nonnull.C: New test.
* g++.dg/ext/attr-noreturn-2.C: New test.
* g++.dg/ext/attr-noreturn.C: New test.
* g++.dg/ext/attr-nothrow-2.C: New test.
* g++.dg/ext/attr-nothrow.C: New test.
* g++.dg/ext/attr-optimize.C: New test.
* g++.dg/ext/attr-pure.C: New test.
* g++.dg/ext/attr-returns-nonnull.C: New test.
* g++.dg/ext/attr-warning.C: New test.
2018-02-27 Nathan Sidwell <nathan@acm.org>
PR c++/84426

View file

@ -0,0 +1,102 @@
// PR c++/83871 - wrong code for attribute const and pure on distinct
// template specializations
// Test to verify that a declaration of an explicit specialization with
// no attributes is diagnosed when the primary template is declared with
// one or more attributes. The warning helps highlight a change in GCC
// 8 from previous versions that copied the attributes from the primary
// to the specialization. It also helps point out simply forgetting to
// declare the specialization with an attribute.
// { dg-do compile }
// { dg-options "-Wmissing-attributes" }
#define ATTR(list) __attribute__ (list)
// Verify that a primary without attributes doesn't cause warnings.
template <class T> void fnoattr ();
template <> void fnoattr<void>();
template <> void ATTR ((cold)) fnoattr<int>();
template <> void ATTR ((hot)) fnoattr<double>();
// Verify that a noreturn primary also doesn't cause warnings.
template <class T> int ATTR ((noreturn)) fnoreturn ();
template <> int fnoreturn<void>();
template <> int ATTR ((cold)) fnoreturn<int>();
template <> int ATTR ((hot)) fnoreturn<double>();
template <class T>
void*
ATTR ((malloc, alloc_size (1)))
missing_all (int); // { dg-message "missing primary template attributes \(.malloc., .alloc_size.|.alloc_size., .malloc.\)" }
template <>
void*
missing_all<char>(int); // { dg-warning "explicit specialization .\[^\n\r\]+. may be missing attributes" }
// Verify that specifying the same attributes in whatever order
// doesn't trigger the warning, even when other attributes are
// added.
template <>
void*
ATTR ((alloc_size (1), malloc))
missing_all<char>(int);
template <>
void*
ATTR ((alloc_size (1))) ATTR ((malloc)) ATTR ((returns_nonnull))
missing_all<char>(int); // T = char, same as above
template <>
void*
ATTR ((hot)) ATTR ((alloc_size (1))) ATTR ((malloc))
missing_all<char>(int); // T = char, same as above
// Verify that the following attributes suppress the warning.
template <> void* ATTR ((error (""))) missing_all<short>(int);
template <> void* ATTR ((deprecated)) missing_all<int>(int);
template <> void* ATTR ((warning (""))) missing_all<double>(int);
template <class T>
void*
ATTR ((malloc, alloc_size (1)))
missing_malloc (int); // { dg-message "missing primary template attribute .malloc." }
template <>
void*
ATTR ((alloc_size (1)))
missing_malloc<char>(int); // { dg-warning "explicit specialization .\[^\n\r\]+. may be missing attributes" }
template <> void* ATTR ((malloc, alloc_size (1))) missing_malloc<short>(int);
template <> void* ATTR ((deprecated)) missing_malloc<int>(int);
template <> void* ATTR ((error (""))) missing_malloc<long>(int);
template <> void* ATTR ((warning (""))) missing_malloc<double>(int);
template <class T>
void*
ATTR ((malloc, alloc_size (1)))
missing_alloc_size (int, int); // { dg-message "missing primary template attribute .alloc_size." }
template <>
void*
ATTR ((malloc))
missing_alloc_size<char>(int, int); // { dg-warning "explicit specialization .\[^\n\r\]+. may be missing attributes" }
template <class T>
void*
ATTR ((nonnull (1)))
missing_nonnull (void*); // { dg-message "missing primary template attribute .nonnull." }
template <>
void*
ATTR ((malloc))
missing_nonnull<char>(void*); // { dg-warning "explicit specialization .\[^\n\r\]+. may be missing attributes" }
template <> void* ATTR ((nonnull (1))) missing_nonnull<short>(void*);
template <> void* ATTR ((deprecated)) missing_nonnull<int>(void*);
template <> void* ATTR ((error (""))) missing_nonnull<long>(void*);
template <> void* ATTR ((warning (""))) missing_nonnull<double>(void*);

View file

@ -0,0 +1,144 @@
// Bug c++/83503 - bogus -Wattributes for const and pure on function template
// specialization
// { dg-do compile }
// { dg-options "-O -Wall -fdump-tree-optimized" }
int global;
template <class T>
int __attribute__ ((pure))
f (T);
template <>
int __attribute__ ((const)) f<int> (int); // { dg-bogus "ignoring attribute .const." }
void f_pure_primary_elim ();
void f_pure_primary_keep ();
void f_const_spec_elim ();
void call_pure_primary_elim (double x)
{
// Only the first call to f(x) must be emitted, the second one
// is expected to be eliminated because the primary template
// is pure.
int i0 = f (x);
int i1 = f (x);
if (i0 != i1)
f_pure_primary_elim ();
}
void call_pure_primary_keep (const char *s)
{
// Both calls to f(x) must be emitted because the primary is
// pure and may read global.
int i0 = f (s);
global = 123;
int i1 = f (s);
if (i0 != i1)
f_pure_primary_keep ();
}
void call_const_spec_elim (int i)
{
// Only the first call to f(x) must be emitted, the second
// one is expected to be eliminated again, this time because
// unlike the pure primary, the specialization is const.
int i0 = f (i);
global = 123;
int i1 = f (i);
if (i0 != i1)
f_const_spec_elim ();
}
template <class T>
int __attribute__ ((const))
g (T);
template <>
int __attribute__ ((pure)) g<int> (int); // { dg-bogus "ignoring attribute .const." }
template <class T>
int __attribute__ ((const))
h (T);
template <class T>
int __attribute__ ((pure))
h (const T*);
template <>
int h<int> (int);
template <>
int h<int*> (int*);
extern void h_const_primary_elim ();
extern void h_pure_cstptr_elim ();
extern void h_cstptr_keep ();
extern void h_int_keep ();
extern void h_intptr_keep ();
void call_const_primary_elim (double x)
{
// Only the first call to h(x) must be emitted, the second one
// is expected to be eliminated.
int i0 = h (x);
int i1 = h (x);
if (i0 != i1) // must be folded into false
h_const_primary_elim (); // must be eliminated
}
void call_pure_cstptr_elim (const void *p)
{
// Only the first call to h(x) must be emitted, the second one
// is expected to be eliminated. This verifies that h<const
// void*>*() is treated as const in this context.
int i0 = h (p);
int i1 = h (p);
if (i0 != i1) // must be folded into false
h_pure_cstptr_elim (); // must be eliminated
}
void call_cstptr_keep (const void *p)
{
// Because of the store to the global, both calls to h(p) must
// be emitted. This verifies that h<const void*>*() is not
// treated as const.
int i0 = h (p);
global = 123;
int i1 = h (p);
if (i0 != i1) // must not be folded
h_cstptr_keep (); // must be emitted
}
void call_int_keep (int i)
{
// Both calls to h(i) must be emitted.
int i0 = h (i);
int i1 = h (i);
if (i0 != i1) // must not be folded
h_int_keep (); // must be emitted
}
void call_intptr_keep (int *ip)
{
// Both calls to h(ip) must be emitted.
int i0 = h (ip);
int i1 = h (ip);
if (i0 != i1) // must not be folded
h_intptr_keep (); // must be emitted
}
// { dg-final { scan-tree-dump-not "f_pure_primary_elim" "optimized" } }
// { dg-final { scan-tree-dump-not "f_const_primary_elim" "optimized" } }
// { dg-final { scan-tree-dump-not "f_const_spec_elim" "optimized" } }
// { dg-final { scan-tree-dump-not "h_pure_cstptr_elim" "optimized" } }
// { dg-final { scan-tree-dump-times "f_pure_primary_keep" 1 "optimized" } }
// { dg-final { scan-tree-dump-times "h_cstptr_keep" 1 "optimized" } }
// { dg-final { scan-tree-dump-times "h_int_keep" 1 "optimized" } }
// { dg-final { scan-tree-dump-times "h_intptr_keep" 1 "optimized" } }

View file

@ -0,0 +1,69 @@
/* PR c++/83871 - wrong code for attribute const and pure on distinct
template specializations
{ dg-do compile }
{ dg-options "-O -Wall" } */
int __attribute__ ((const)) fconst_none ();
int fconst_none ();
void test_const_none_failed ();
void func_const_none ()
{
int i0 = fconst_none ();
int i1 = fconst_none ();
if (i0 != i1)
test_const_none_failed ();
// { dg-final { scan-tree-dump-not "test_const_none_failed" "optimized" } }
}
int fnone_const ();
int __attribute__ ((const)) fnone_const ();
void test_none_const_failed ();
void func_none_const ()
{
int i0 = fnone_const ();
int i1 = fnone_const ();
if (i0 != i1)
test_none_const_failed ();
// { dg-final { scan-tree-dump-not "test_none_const_failed" "optimized" } }
}
template <class T>
int __attribute__ ((const)) fconst_none (T);
template <class T>
int fconst_none (T);
void template_const_none ()
{
int i0 = fconst_none<int> (0);
int i1 = fconst_none<int> (0);
if (i0 != i1)
test_const_none_failed ();
// { dg-final { scan-tree-dump-not "test_const_none_failed" "optimized" } }
}
template <class T>
int fnone_const (T);
template <class T>
int __attribute__ ((const)) fnone_const (T);
void test_fnone_const ()
{
int i0 = fnone_const<int> (0);
int i1 = fnone_const<int> (0);
if (i0 != i1)
test_none_const_failed ();
// { dg-final { scan-tree-dump-not "test_none_const_failed" "optimized" } }
}

View file

@ -0,0 +1,35 @@
// Bug c++/83871 - wrong code due to attributes on distinct template
// specializations
// Test to verify that an explicit template specifialization does not
// "inherit" attribute deprecated from a primary template declared
// with it.
// { dg-do compile }
// { dg-options "-Wall -fdump-tree-optimized" }
struct Special;
template <class T>
void fdeprecated_primary ();
// The primary isn't deprecated at this point so the declaration
// of its specialization should not be diagnosed.
template <>
void fdeprecated_primary<Special> (); // { dg-bogus "deprecated" }
template <class T>
void __attribute__ ((deprecated))
fdeprecated_primary ();
void use_primary ()
{
// Verify that uses of the now deprecacted primary are diagnosed.
fdeprecated_primary<void>(); // { dg-warning "deprecated" "bug 84542" { xfail *-*-* } }
fdeprecated_primary<int>(); // { dg-warning "deprecated" "bug 84542" { xfail *-*-* } }
}
void use_special ()
{
// Verify that the use of the non-deprecated specializatoin
// is not diagnosed.
fdeprecated_primary<Special>();
}

View file

@ -0,0 +1,49 @@
// Bug c++/83503 - bogus -Wattributes for const and pure on function template
// specialization
// Test to verify that attribute malloc on multiple declarations of
// the same ordinary function are merged.
// { dg-do compile }
// { dg-options "-O -Wall -fdump-tree-optimized" }
void* __attribute__ ((malloc))
fmalloc_none (unsigned);
void*
fmalloc_none (unsigned);
static char a[8];
void fmalloc_none_failed ();
void test_fmalloc_none (void)
{
void *p = fmalloc_none (1);
if (!p)
return;
if (p == a) // must be false
fmalloc_none_failed (); // should be eliminated
// Verify that the call to fmalloc_none() is eliminated.
// { dg-final { scan-tree-dump-not "fmalloc_none_failed" "optimized" } }
}
void* fnone_malloc (unsigned);
void* __attribute__ ((malloc))
fnone_malloc (unsigned);
void fnone_malloc_failed ();
void test_fnone_malloc (void)
{
void *p = fnone_malloc (1);
if (!p)
return;
if (p == a) // must be false
fnone_malloc_failed (); // should be eliminated
// Verify that the call to fnone_malloc() is eliminated.
// { dg-final { scan-tree-dump-not "fnone_malloc_failed" "optimized" } }
}

View file

@ -0,0 +1,69 @@
// Bug c++/83503 - bogus -Wattributes for const and pure on function template
// specialization
// Test to verify that an explicit template specifialization does not
// "inherit" attribute malloc from a primary template declared with one.
// { dg-do compile }
// { dg-options "-O -Wall -fdump-tree-optimized" }
template <class>
void* __attribute__ ((malloc))
fmalloc (unsigned);
template <>
void*
fmalloc<int>(unsigned); // { dg-warning "may be missing attributes" }
static char a[8];
void fmalloc_void_malloc ();
void fmalloc_int_not_malloc ();
void test_fmalloc_primary (void)
{
void *p = fmalloc<void>(1);
if (!p)
return;
if (p == a) // must be false
fmalloc_void_malloc (); // should be eliminated
// Verify that the call to fmalloc_void_malloc() is eliminated.
// { dg-final { scan-tree-dump-not "fmalloc_void_malloc" "optimized" } }
}
void test_fmalloc_spec_none (void)
{
void *p = fmalloc<int>(1);
if (!p)
return;
if (p == a) // can be true
fmalloc_int_not_malloc (); // must not be eliminated
// Verify that the call to fmalloc_int_not_malloc() is retained.
// { dg-final { scan-tree-dump-times "fmalloc_int_not_malloc" 1 "optimized" } }
}
template <>
void*
fmalloc<long>(unsigned); // { dg-warning "may be missing attributes" }
template <>
void* __attribute__ ((malloc))
fmalloc<long>(unsigned);
void fmalloc_long_malloc ();
void test_fmalloc_spec_malloc (void)
{
void *p = fmalloc<long>(1);
if (!p)
return;
if (p == a) // can be true
fmalloc_long_malloc (); // must not be eliminated
// Verify that the call to fmalloc_long_malloc() is eliminated.
// { dg-final { scan-tree-dump-not "fmalloc_long_malloc" "optimized" } }
}

View file

@ -0,0 +1,73 @@
// Bug c++/83871 - wrong code due to attributes on distinct template
// specializations
// Test to verify that an explicit template specifialization does not
// "inherit" attributes always_inline or noinline from a primary template
// declared with either. Unlike attr-noinline.C, this test enables
// optimization to verify that noinline prevents inlining.
// { dg-do compile }
// { dg-options "-O2 -Wall -fdump-tree-optimized" }
enum Special { };
int global;
template <class T>
inline void __attribute__ ((always_inline))
falways_inline_noinline ()
{
// Create a side-effect that's unique to this function.
global = __LINE__;
}
template <>
void __attribute__ ((noinline))
falways_inline_noinline<Special>()
{
global = __LINE__;
}
// Verify that a call to the primary is inlined but one to
// the explicit specialization is not.
void test_elim_primary_1 (void)
{
// Should be inlined.
falways_inline_noinline<void>();
// { dg-final { scan-tree-dump-not "falways_inline_noinline<void> *\\(\\)" "optimized" } }
}
void test_keep_special_1 (void)
{
// Should not be inlined.
falways_inline_noinline<Special>();
// { dg-final { scan-tree-dump-times "falways_inline_noinline<Special> *\\(\\);" 1 "optimized" } }
}
template <class T>
void __attribute__ ((noinline))
fnoinline_always_inline ()
{
global = __LINE__;
}
template <>
inline void __attribute__ ((always_inline))
fnoinline_always_inline<Special>() // { dg-bogus "follows declaration" }
{
global = __LINE__;
}
void test_keep_primary_2 (void)
{
// Should not be inlined.
fnoinline_always_inline<void>();
// { dg-final { scan-tree-dump-times "fnoinline_always_inline<void> *\\(\\);" 1 "optimized" } }
}
void test_elim_special_2 (void)
{
// Should be inlined.
fnoinline_always_inline<Special>();
// { dg-final { scan-tree-dump-not "fnoinline_always_inline<Special> *\\(\\);" optimized" } }
}

View file

@ -0,0 +1,128 @@
// Bug c++/83871 - wrong code due to attributes on distinct template
// specializations
// Test to verify that an explicit template specifialization does not
// "inherit" attributes always_inline or noinline from a primary template
// declared with either. The test disables optimization to verify that
// always_inline forces inlining.
// { dg-do compile }
// { dg-options "-O0 -Wall -fdump-tree-optimized" }
enum Special { };
template <class T>
inline void __attribute__ ((always_inline))
falways_inline_none ()
{
// Primary template should always be inlined, even without optimization.
asm (""); // induce a no-op "side-effect"
}
template <>
inline void
falways_inline_none<Special>()
{
// The specialization should not be inlined without optimization, even
// though it's declared inline.
asm ("");
}
// Verify that a call to the primary is inlined but one to
// the explicit specialization is not.
void test_elim_primary_1 (void)
{
// Should be inlined.
falways_inline_none<void>();
// { dg-final { scan-tree-dump-not "falways_inline_none<void> *\\(\\)" "optimized" } }
}
void test_keep_special_1 (void)
{
// Should not be inlined.
falways_inline_none<Special>();
// { dg-final { scan-tree-dump-times "falways_inline_none<Special> *\\(\\);" 1 "optimized" } }
}
template <class T>
inline void __attribute__ ((always_inline))
falways_inline_noinline ()
{
asm (""); // induce a no-op "side-effect"
}
template <>
void __attribute__ ((noinline))
falways_inline_noinline<Special>() { asm (""); }
// Verify that a call to the primary is inlined but one to
// the explicit specialization is not.
void test_elim_primary_2 (void)
{
falways_inline_noinline<void>();
// { dg-final { scan-tree-dump-not "falways_inline_noinline<void> *\\(\\)" "optimized" } }
}
void test_keep_special_2 (void)
{
falways_inline_noinline<Special>();
// { dg-final { scan-tree-dump-times "falways_inline_noinline<Special> *\\(\\);" 1 "optimized" } }
}
template <class T>
inline void
fnone_always_inline ()
{
asm (""); // induce a no-op "side-effect"
}
template <>
inline void __attribute__ ((always_inline))
fnone_always_inline<Special>() { asm (""); }
// Verify that a call to the primary is not inlined but one to
// the explicit specialization is.
void test_keep_primary_3 (void)
{
fnone_always_inline<void>();
// { dg-final { scan-tree-dump-times "fnone_always_inline<void> *\\(\\);" 1 "optimized" } }
}
void test_elim_special_3 (void)
{
fnone_always_inline<Special>();
// { dg-final { scan-tree-dump-not "fnone_always_inline<Special> *\\(\\);" optimized" } }
}
template <class T>
void __attribute__ ((noinline))
fnoinline_always_inline ()
{
asm (""); // induce a no-op "side-effect"
}
template <>
inline void __attribute__ ((always_inline))
fnoinline_always_inline<Special>() // { dg-bogus "follows declaration" }
{
asm ("");
}
// Verify that a call to the primary is not inlined but one to
// the explicit specialization is.
void test_keep_primary_4 (void)
{
fnoinline_always_inline<void>();
// { dg-final { scan-tree-dump-times "fnoinline_always_inline<void> *\\(\\);" 1 "optimized" } }
}
void test_elim_special_4 (void)
{
fnoinline_always_inline<Special>();
// { dg-final { scan-tree-dump-not "fnoinline_always_inline<Special> *\\(\\);" optimized" } }
}

View file

@ -0,0 +1,31 @@
// Bug c++/83871 - wrong code due to attributes on distinct template
// specializations
// Test to verify that an explicit function template specifialization
// does not "inherit" attribute nonnull from an argument declared with
// one in the primary template.
// { dg-do compile }
// { dg-options "-O -Wall -fdump-tree-optimized" }
template <class T>
void __attribute__ ((nonnull (1)))
f (T*, T*, T*);
template <>
void
f<int>(int*, int*, int*); // { dg-warning "may be missing attributes" }
template <>
void __attribute__ ((nonnull (3)))
f<float>(float*, float*, float*);
void test_nonnull (void)
{
f<void>(0, 0, 0); // { dg-warning "null argument where non-null required \\\(argument 1\\\)" }
f<int>(0, 0, 0); // { dg-bogus "null argument" }
f<float>(0, 0, 0);
// { dg-bogus "null argument where non-null required \\\(argument 1\\\)" "" { target *-*-* } .-1 }
// { dg-warning "null argument where non-null required \\\(argument 3\\\)" "" { target *-*-* } .-2 }
}

View file

@ -0,0 +1,47 @@
/* PR c++/83871 - wrong code for attribute const and pure on distinct
template specializations
Test to verify that attributes noreturn on multiple declarations of
the same function are merged.
{ dg-do compile }
{ dg-options "-O -fdump-tree-eh" } */
int __attribute__ ((noreturn)) fnoreturn ();
void fnoreturn_failed ();
int test_noreturn () throw ()
{
fnoreturn ();
fnoreturn_failed ();
// Verify that the call to fnoreturn_failed() is eliminated.
// { dg-final { scan-tree-dump-not "fnoreturn_failed" "optimized" } }
// Expect no -Wreturn-type warning despite the absence of a return
// statement in a non-void function.
}
int __attribute__ ((noreturn)) fnoreturn_none ();
int fnoreturn_none ();
void fnoreturn_none_failed ();
int test_noreturn_none ()
{
fnoreturn_none ();
fnoreturn_none_failed ();
// { dg-final { scan-tree-dump-not "fnoreturn_none_failed" "optimized" } }
}
int fnone_noreturn ();
int __attribute__ ((noreturn)) fnone_noreturn ();
void fnone_noreturn_failed ();
int test_none_noreturn () throw ()
{
fnone_noreturn ();
fnone_noreturn_failed ();
// { dg-final { scan-tree-dump-not "fnone_noreturn_failed" "optimized" } }
}

View file

@ -0,0 +1,80 @@
// Bug c++/83871 - wrong code due to attributes on distinct template
// specializations
// Test to verify that an explicit template specifialization does not
// "inherit" attribute noreturn from a primary template declared with
// one.
// { dg-do compile }
// { dg-options "-O -Wall -fdump-tree-optimized" }
struct Noreturn { };
struct Returns { };
// Primary declared noreturn but explicit specialization is not.
template <class T> int __attribute__ ((noreturn)) f ();
template <> int f<Returns>();
// Explicit specialization is noreturn but primary is not.
template <class T> int g ();
template <> int __attribute__ ((noreturn)) g<Noreturn>();
int val;
int test_primary_noreturn (char, short)
{
// Only the first call should be emitted, the second one should
// be eliminated because the first one doesn't return.
val = f<char>() + f<short>();
} // expect no -Wreturn-type warning here
int test_noreturn (int)
{
// Call should be retained.
f<int>();
} // expect no -Wreturn-type warning here
int test_special_return (int)
{
// Both calls must be emitted.
int val = f<Returns>() + f<Returns>();
(void)&val;
} // { dg-warning "no return statement in function returning non-void" }
int test_primary_return (void)
{
int val = g<char>() + g<int>();
(void)&val;
} // { dg-warning "no return statement in function returning non-void" }
int test_special_noreturn (int, long)
{
g<Noreturn>();
} // expect no -Wreturn-type warning here
// Verify that the call to f<short>() above is eliminated but the call
// to f<int>() and the two calls to f<Returns>() are retained.
// { dg-final { scan-tree-dump-not "f<short>" "optimized" } }
// { dg-final { scan-tree-dump-times "f<Returns>" 2 "optimized" } }
// Verify that the second call to f<Returns>() in test_special_return()
// is followed by __builtin_unreachable() because there is no return
// statement in the function.
// { dg-final { scan-tree-dump-times "f<Returns> \\(\\);\[\n\r \]+__builtin_unreachable" 1 "optimized" } }
// Verify that the call to g<short>() above is eliminated but the call
// to g<char>() and to g<Noreturn>() are both retained.
// { dg-final { scan-tree-dump-not "g<short>" "optimized" } }
// { dg-final { scan-tree-dump-times "g<char>" 1 "optimized" } }
// { dg-final { scan-tree-dump-times "g<Noreturn>" 1 "optimized" } }
// Verify that the call to g<int>() in test_primary_return() is
// followed by __builtin_unreachable() because there is no return
// statement in the function.
// { dg-final { scan-tree-dump-times "g<int> *\\(\\);\[\n\r \]+__builtin_unreachable" 1 "optimized" } }
// Verify that the call to g<Noreturn>() in test_special_noreturn()
// is not followed by __builtin_unreachable() even though there is no
// return statement in the function.
// { dg-final { scan-tree-dump-times "g<Noreturn> *\\(\\);\[\n\r \]+__builtin_unreachable" 0 "optimized" } }

View file

@ -0,0 +1,48 @@
/* PR c++/83871 - wrong code for attribute const and pure on distinct
template specializations
Test to verify that attributes nothrow on multiple declarations of
the same function are merged.
{ dg-do compile }
{ dg-options "-O -fdump-tree-eh" } */
void __attribute__ ((nothrow)) fnothrow ();
void test_nothrow () throw ()
{
// No exception handling necessary around the call to fnothrow().
fnothrow ();
}
void __attribute__ ((nothrow)) fnothrow_none ();
void fnothrow_none ();
void test_nothrow_none () throw ()
{
// No exception handling necessary around the call to fnothrow_none().
fnothrow_none ();
}
void fnone_nothrow ();
void __attribute__ ((nothrow)) fnone_nothrow ();
void test_none_nothrow () throw ()
{
// No exception handling necessary around the call to fnone_nothrow().
fnone_nothrow ();
}
int __attribute__ ((nothrow)) fnothrow_noreturn_none ();
int __attribute__ ((noreturn)) fnothrow_noreturn_none ();
int fnothrow_noreturn_none ();
int test_nothrow_noreturn_none () throw ()
{
// No exception handling necessary around the call().
// No -Wreturn-value should be emitted because the function is
// declared noreturn.
fnothrow_noreturn_none ();
}
// 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" } }

View file

@ -0,0 +1,46 @@
// Bug c++/83871 - wrong code due to attributes on distinct template
// specializations
// Test to verify that an explicit template specifialization does not
// "inherit" attribute nothrow from a primary template declared with one.
// { dg-do compile }
// { dg-options "-O -Wall -fdump-tree-optimized" }
template <class T>
void __attribute__ ((nothrow))
f ();
template <>
void f<int>();
void f_void_nothrow ();
void f_int_maythrow ();
void fv (void)
{
try
{
f<void>();
}
catch (...) // cannot be be reached
{
f_void_nothrow (); // should be eliminated
}
}
void fi (void)
{
try
{
f<int>();
}
catch (...) // may be reached
{
f_int_maythrow (); // must not be eliminated
}
}
// Verify that the call to f_void_nothrow() is eliminated but
// the call to f_int_maythrow() is retained.
// { dg-final { scan-tree-dump-not "f_void_nothrow" "optimized" } }
// { dg-final { scan-tree-dump-times "f_int_maythrow" 1 "optimized" } }

View file

@ -0,0 +1,46 @@
// Bug c++/83871 - wrong code due to attributes on distinct template
// specializations
// Test to verify that an explicit template specifialization does not
// "inherit" attribute optimize from a primary template declared with
// one.
// { dg-do compile }
// { dg-options "-O2 -Wall -fdump-tree-optimized" }
enum Special { };
void foptimize_none_primary_failed ();
template <class T>
void __attribute__ ((optimize ("no-printf-return-value")))
foptimize_none ()
{
// The call to snprintf and the test should be retained.
if (2 != __builtin_snprintf (0, 0, "%hhx", 0x12))
foptimize_none_primary_failed ();
}
void foptimize_none_special_failed ();
template <>
inline void
foptimize_none<Special>()
{
// The whole if statement should be eliminated.
if (3 != __builtin_snprintf (0, 0, "1%hhx", 0x12))
foptimize_none_special_failed ();
}
void test_primary ()
{
foptimize_none<void>();
// { dg-final { scan-tree-dump-times "foptimize_none_primary_failed *\\(\\)" 1 "optimized" } }
}
void test_special ()
{
// Should be eliminated.
foptimize_none<Special>();
// { dg-final { scan-tree-dump-not "foptimize_none_special_failed *\\(\\)" "optimized" } }
}
// { dg-final { scan-tree-dump-times "__builtin_snprintf" 1 "optimized" } }

View file

@ -0,0 +1,69 @@
/* PR c++/83871 - wrong code for attribute const and pure on distinct
template specializations
{ dg-do compile }
{ dg-options "-O -Wall" } */
int __attribute__ ((pure)) fpure_none ();
int fpure_none ();
void test_pure_none_failed ();
void func_pure_none ()
{
int i0 = fpure_none ();
int i1 = fpure_none ();
if (i0 != i1)
test_pure_none_failed ();
// { dg-final { scan-tree-dump-not "test_pure_none_failed" "optimized" } }
}
int fnone_pure ();
int __attribute__ ((pure)) fnone_pure ();
void test_none_pure_failed ();
void func_none_pure ()
{
int i0 = fnone_pure ();
int i1 = fnone_pure ();
if (i0 != i1)
test_none_pure_failed ();
// { dg-final { scan-tree-dump-not "test_none_pure_failed" "optimized" } }
}
template <class T>
int __attribute__ ((pure)) fpure_none (T);
template <class T>
int fpure_none (T);
void template_pure_none ()
{
int i0 = fpure_none<int> (0);
int i1 = fpure_none<int> (0);
if (i0 != i1)
test_pure_none_failed ();
// { dg-final { scan-tree-dump-not "test_pure_none_failed" "optimized" } }
}
template <class T>
int fnone_pure (T);
template <class T>
int __attribute__ ((pure)) fnone_pure (T);
void test_fnone_pure ()
{
int i0 = fnone_pure<int> (0);
int i1 = fnone_pure<int> (0);
if (i0 != i1)
test_none_pure_failed ();
// { dg-final { scan-tree-dump-not "test_none_pure_failed" "optimized" } }
}

View file

@ -0,0 +1,42 @@
// Bug c++/83871 - wrong code due to attributes on distinct template
// specializations
// Test to verify that an explicit function template specifialization
// does not "inherit" attribute nonnull from an argument declared with
// one in the primary template.
// { dg-do compile }
// { dg-options "-O -Wall -fdump-tree-optimized" }
template <class T>
void* __attribute__ ((returns_nonnull))
g ();
template <>
void*
g<int>();
extern void g_void_returns_nonnull ();
extern void g_int_may_return_null ();
void test_returns_nonnull ()
{
void *p = g<void>();
if (!p)
g_void_returns_nonnull ();
(void)&p;
}
void test_may_return_null ()
{
void *p = g<int>();
if (!p)
g_int_may_return_null ();
(void)&p;
}
// Verify that the call to g_void_returns_nonnull() is eliminated but
// the call to g_int_may_return_null() is retained.
// { dg-final { scan-tree-dump-not "g_void_returns_nonnull" "optimized" } }
// { dg-final { scan-tree-dump-times "g_int_may_return_null" 1 "optimized" } }

View file

@ -0,0 +1,49 @@
// Bug c++/83871 - wrong code due to attributes on distinct template
// specializations
// Test to verify that an explicit template specifialization does not
// "inherit" attribute warning from a primary template declared with
// it.
// { dg-do compile }
// { dg-options "-Wall -fdump-tree-optimized" }
struct Special;
// Primary has no attributes here.
template <class T>
void fwarn_primary ();
// Uses of the primary template, including declarations of its
// specializations, should not be diagnosed until after it has
// been redeclared with attribute warning.
template <>
void fwarn_primary<Special> ();
void use_primary_before_warning ()
{
// Verify that uses of the primary are not diagnosed.
fwarn_primary<char>();
fwarn_primary<short>();
}
// Redeclare the primary with attribute warning.
template <class T>
void __attribute__ ((warning ("primary")))
fwarn_primary ();
// Attribute warning is special in that it only warns for functions
// that are actually used, not those that are only declared.
template <>
void fwarn_primary<double> ();
void use_primary_after_warning ()
{
// Verify that uses of the redeclared primary are diagnosed.
fwarn_primary<int>(); // { dg-warning "primary" }
fwarn_primary<long>(); // { dg-warning "primary" }
}
void use_special ()
{
// Verify that the use of the specializatoin is not diagnosed.
fwarn_primary<Special>();
}