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:
parent
1c89478aef
commit
d4cfd486eb
27 changed files with 1404 additions and 38 deletions
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
105
gcc/cp/decl.c
105
gcc/cp/decl.c
|
@ -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;
|
||||
|
||||
|
|
123
gcc/cp/pt.c
123
gcc/cp/pt.c
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
102
gcc/testsuite/g++.dg/Wmissing-attributes.C
Normal file
102
gcc/testsuite/g++.dg/Wmissing-attributes.C
Normal 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*);
|
144
gcc/testsuite/g++.dg/ext/attr-const-pure.C
Normal file
144
gcc/testsuite/g++.dg/ext/attr-const-pure.C
Normal 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" } }
|
69
gcc/testsuite/g++.dg/ext/attr-const.C
Normal file
69
gcc/testsuite/g++.dg/ext/attr-const.C
Normal 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" } }
|
||||
}
|
35
gcc/testsuite/g++.dg/ext/attr-deprecated-2.C
Normal file
35
gcc/testsuite/g++.dg/ext/attr-deprecated-2.C
Normal 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>();
|
||||
}
|
49
gcc/testsuite/g++.dg/ext/attr-malloc-2.C
Normal file
49
gcc/testsuite/g++.dg/ext/attr-malloc-2.C
Normal 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" } }
|
||||
}
|
69
gcc/testsuite/g++.dg/ext/attr-malloc.C
Normal file
69
gcc/testsuite/g++.dg/ext/attr-malloc.C
Normal 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" } }
|
||||
}
|
73
gcc/testsuite/g++.dg/ext/attr-noinline-2.C
Normal file
73
gcc/testsuite/g++.dg/ext/attr-noinline-2.C
Normal 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" } }
|
||||
}
|
128
gcc/testsuite/g++.dg/ext/attr-noinline.C
Normal file
128
gcc/testsuite/g++.dg/ext/attr-noinline.C
Normal 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" } }
|
||||
}
|
31
gcc/testsuite/g++.dg/ext/attr-nonnull.C
Normal file
31
gcc/testsuite/g++.dg/ext/attr-nonnull.C
Normal 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 }
|
||||
}
|
47
gcc/testsuite/g++.dg/ext/attr-noreturn-2.C
Normal file
47
gcc/testsuite/g++.dg/ext/attr-noreturn-2.C
Normal 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" } }
|
||||
}
|
80
gcc/testsuite/g++.dg/ext/attr-noreturn.C
Normal file
80
gcc/testsuite/g++.dg/ext/attr-noreturn.C
Normal 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" } }
|
48
gcc/testsuite/g++.dg/ext/attr-nothrow-2.C
Normal file
48
gcc/testsuite/g++.dg/ext/attr-nothrow-2.C
Normal 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" } }
|
46
gcc/testsuite/g++.dg/ext/attr-nothrow.C
Normal file
46
gcc/testsuite/g++.dg/ext/attr-nothrow.C
Normal 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" } }
|
46
gcc/testsuite/g++.dg/ext/attr-optimize.C
Normal file
46
gcc/testsuite/g++.dg/ext/attr-optimize.C
Normal 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" } }
|
69
gcc/testsuite/g++.dg/ext/attr-pure.C
Normal file
69
gcc/testsuite/g++.dg/ext/attr-pure.C
Normal 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" } }
|
||||
}
|
42
gcc/testsuite/g++.dg/ext/attr-returns-nonnull.C
Normal file
42
gcc/testsuite/g++.dg/ext/attr-returns-nonnull.C
Normal 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" } }
|
49
gcc/testsuite/g++.dg/ext/attr-warning.C
Normal file
49
gcc/testsuite/g++.dg/ext/attr-warning.C
Normal 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>();
|
||||
}
|
Loading…
Add table
Reference in a new issue