From: Martin Sebor Date: Tue, 27 Feb 2018 22:28:21 +0000 (+0000) Subject: PR c++/83871 - wrong code for attribute const and pure on distinct template specializ... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d4cfd486ebe3fadb7a67c53c24843770a1d8ba72;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 292bf8559a6..f99e782d8ae 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2018-02-27 Martin Sebor + + 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 PR translation/84207 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 49cfea95b3d..240cc7bccda 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2018-02-27 Martin Sebor + + PR c++/83871 + * c.opt (-Wmissing-attributes): New option. + 2018-02-21 Martin Liska * c.opt (Wcatch-value=): Add IntegerRange. diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 421b1464545..a4c8c8ffcb3 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -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) ; diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 20c15e4bec1..9b4dd033be4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2018-02-27 Martin Sebor + + 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 PR c++/71546 - lambda init-capture with qualified-id. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6e83a29139b..743dd340245 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index cf917731f0c..6af774fc0fd 100644 --- a/gcc/cp/decl.c +++ b/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; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a3da40912d6..ae777db82fe 100644 --- a/gcc/cp/pt.c +++ b/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 #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 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index e70e2bad4d8..8d366c626ba 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 +T* __attribute__ ((malloc, alloc_size (1))) +allocate (size_t); + +template <> +void* __attribute__ ((malloc)) // missing alloc_size +allocate (size_t); +@end smallexample + @item -Wmissing-braces @opindex Wmissing-braces @opindex Wno-missing-braces diff --git a/gcc/print-tree.c b/gcc/print-tree.c index cba8bacdb8a..caf5f260147 100644 --- a/gcc/print-tree.c +++ b/gcc/print-tree.c @@ -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)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index eaf0d6a21b7..b957cb7f52f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,25 @@ +2018-02-27 Martin Sebor + + 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 PR c++/84426 diff --git a/gcc/testsuite/g++.dg/Wmissing-attributes.C b/gcc/testsuite/g++.dg/Wmissing-attributes.C new file mode 100644 index 00000000000..f4ebce1498d --- /dev/null +++ b/gcc/testsuite/g++.dg/Wmissing-attributes.C @@ -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 void fnoattr (); + +template <> void fnoattr(); +template <> void ATTR ((cold)) fnoattr(); +template <> void ATTR ((hot)) fnoattr(); + +// Verify that a noreturn primary also doesn't cause warnings. +template int ATTR ((noreturn)) fnoreturn (); + +template <> int fnoreturn(); +template <> int ATTR ((cold)) fnoreturn(); +template <> int ATTR ((hot)) fnoreturn(); + + +template +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(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(int); + +template <> +void* +ATTR ((alloc_size (1))) ATTR ((malloc)) ATTR ((returns_nonnull)) +missing_all(int); // T = char, same as above + +template <> +void* +ATTR ((hot)) ATTR ((alloc_size (1))) ATTR ((malloc)) +missing_all(int); // T = char, same as above + +// Verify that the following attributes suppress the warning. +template <> void* ATTR ((error (""))) missing_all(int); +template <> void* ATTR ((deprecated)) missing_all(int); +template <> void* ATTR ((warning (""))) missing_all(int); + + +template +void* +ATTR ((malloc, alloc_size (1))) +missing_malloc (int); // { dg-message "missing primary template attribute .malloc." } + +template <> +void* +ATTR ((alloc_size (1))) +missing_malloc(int); // { dg-warning "explicit specialization .\[^\n\r\]+. may be missing attributes" } + +template <> void* ATTR ((malloc, alloc_size (1))) missing_malloc(int); +template <> void* ATTR ((deprecated)) missing_malloc(int); +template <> void* ATTR ((error (""))) missing_malloc(int); +template <> void* ATTR ((warning (""))) missing_malloc(int); + +template +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(int, int); // { dg-warning "explicit specialization .\[^\n\r\]+. may be missing attributes" } + + +template +void* +ATTR ((nonnull (1))) +missing_nonnull (void*); // { dg-message "missing primary template attribute .nonnull." } + +template <> +void* +ATTR ((malloc)) +missing_nonnull(void*); // { dg-warning "explicit specialization .\[^\n\r\]+. may be missing attributes" } + +template <> void* ATTR ((nonnull (1))) missing_nonnull(void*); +template <> void* ATTR ((deprecated)) missing_nonnull(void*); +template <> void* ATTR ((error (""))) missing_nonnull(void*); +template <> void* ATTR ((warning (""))) missing_nonnull(void*); diff --git a/gcc/testsuite/g++.dg/ext/attr-const-pure.C b/gcc/testsuite/g++.dg/ext/attr-const-pure.C new file mode 100644 index 00000000000..f7c6f3b674c --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-const-pure.C @@ -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 +int __attribute__ ((pure)) +f (T); + +template <> +int __attribute__ ((const)) f (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 +int __attribute__ ((const)) +g (T); + +template <> +int __attribute__ ((pure)) g (int); // { dg-bogus "ignoring attribute .const." } + +template +int __attribute__ ((const)) +h (T); + +template +int __attribute__ ((pure)) +h (const T*); + +template <> +int h (int); + +template <> +int h (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*() 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*() 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" } } diff --git a/gcc/testsuite/g++.dg/ext/attr-const.C b/gcc/testsuite/g++.dg/ext/attr-const.C new file mode 100644 index 00000000000..a9884db765f --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-const.C @@ -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 +int __attribute__ ((const)) fconst_none (T); + +template +int fconst_none (T); + +void template_const_none () +{ + int i0 = fconst_none (0); + int i1 = fconst_none (0); + if (i0 != i1) + test_const_none_failed (); + + // { dg-final { scan-tree-dump-not "test_const_none_failed" "optimized" } } +} + + +template +int fnone_const (T); + +template +int __attribute__ ((const)) fnone_const (T); + +void test_fnone_const () +{ + int i0 = fnone_const (0); + int i1 = fnone_const (0); + if (i0 != i1) + test_none_const_failed (); + + // { dg-final { scan-tree-dump-not "test_none_const_failed" "optimized" } } +} diff --git a/gcc/testsuite/g++.dg/ext/attr-deprecated-2.C b/gcc/testsuite/g++.dg/ext/attr-deprecated-2.C new file mode 100644 index 00000000000..bf9041506d1 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-deprecated-2.C @@ -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 +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 (); // { dg-bogus "deprecated" } + +template +void __attribute__ ((deprecated)) +fdeprecated_primary (); + +void use_primary () +{ + // Verify that uses of the now deprecacted primary are diagnosed. + fdeprecated_primary(); // { dg-warning "deprecated" "bug 84542" { xfail *-*-* } } + fdeprecated_primary(); // { dg-warning "deprecated" "bug 84542" { xfail *-*-* } } +} + +void use_special () +{ + // Verify that the use of the non-deprecated specializatoin + // is not diagnosed. + fdeprecated_primary(); +} diff --git a/gcc/testsuite/g++.dg/ext/attr-malloc-2.C b/gcc/testsuite/g++.dg/ext/attr-malloc-2.C new file mode 100644 index 00000000000..600d430468c --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-malloc-2.C @@ -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" } } +} diff --git a/gcc/testsuite/g++.dg/ext/attr-malloc.C b/gcc/testsuite/g++.dg/ext/attr-malloc.C new file mode 100644 index 00000000000..3cbb41407ea --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-malloc.C @@ -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 +void* __attribute__ ((malloc)) +fmalloc (unsigned); + +template <> +void* +fmalloc(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(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(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(unsigned); // { dg-warning "may be missing attributes" } + +template <> +void* __attribute__ ((malloc)) +fmalloc(unsigned); + +void fmalloc_long_malloc (); + +void test_fmalloc_spec_malloc (void) +{ + void *p = fmalloc(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" } } +} diff --git a/gcc/testsuite/g++.dg/ext/attr-noinline-2.C b/gcc/testsuite/g++.dg/ext/attr-noinline-2.C new file mode 100644 index 00000000000..4aab4f16f1e --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-noinline-2.C @@ -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 +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() +{ + 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(); +// { dg-final { scan-tree-dump-not "falways_inline_noinline *\\(\\)" "optimized" } } +} + +void test_keep_special_1 (void) +{ + // Should not be inlined. + falways_inline_noinline(); +// { dg-final { scan-tree-dump-times "falways_inline_noinline *\\(\\);" 1 "optimized" } } +} + + +template +void __attribute__ ((noinline)) +fnoinline_always_inline () +{ + global = __LINE__; +} + +template <> +inline void __attribute__ ((always_inline)) +fnoinline_always_inline() // { dg-bogus "follows declaration" } +{ + global = __LINE__; +} + +void test_keep_primary_2 (void) +{ + // Should not be inlined. + fnoinline_always_inline(); +// { dg-final { scan-tree-dump-times "fnoinline_always_inline *\\(\\);" 1 "optimized" } } +} + +void test_elim_special_2 (void) +{ + // Should be inlined. + fnoinline_always_inline(); +// { dg-final { scan-tree-dump-not "fnoinline_always_inline *\\(\\);" optimized" } } +} diff --git a/gcc/testsuite/g++.dg/ext/attr-noinline.C b/gcc/testsuite/g++.dg/ext/attr-noinline.C new file mode 100644 index 00000000000..b09037bd1a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-noinline.C @@ -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 +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() +{ + // 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(); +// { dg-final { scan-tree-dump-not "falways_inline_none *\\(\\)" "optimized" } } +} + +void test_keep_special_1 (void) +{ + // Should not be inlined. + falways_inline_none(); +// { dg-final { scan-tree-dump-times "falways_inline_none *\\(\\);" 1 "optimized" } } +} + + +template +inline void __attribute__ ((always_inline)) +falways_inline_noinline () +{ + asm (""); // induce a no-op "side-effect" +} + +template <> +void __attribute__ ((noinline)) +falways_inline_noinline() { 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(); +// { dg-final { scan-tree-dump-not "falways_inline_noinline *\\(\\)" "optimized" } } +} + +void test_keep_special_2 (void) +{ + falways_inline_noinline(); +// { dg-final { scan-tree-dump-times "falways_inline_noinline *\\(\\);" 1 "optimized" } } +} + + +template +inline void +fnone_always_inline () +{ + asm (""); // induce a no-op "side-effect" +} + +template <> +inline void __attribute__ ((always_inline)) +fnone_always_inline() { 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(); +// { dg-final { scan-tree-dump-times "fnone_always_inline *\\(\\);" 1 "optimized" } } +} + +void test_elim_special_3 (void) +{ + fnone_always_inline(); +// { dg-final { scan-tree-dump-not "fnone_always_inline *\\(\\);" optimized" } } +} + + +template +void __attribute__ ((noinline)) +fnoinline_always_inline () +{ + asm (""); // induce a no-op "side-effect" +} + +template <> +inline void __attribute__ ((always_inline)) +fnoinline_always_inline() // { 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(); +// { dg-final { scan-tree-dump-times "fnoinline_always_inline *\\(\\);" 1 "optimized" } } +} + +void test_elim_special_4 (void) +{ + fnoinline_always_inline(); +// { dg-final { scan-tree-dump-not "fnoinline_always_inline *\\(\\);" optimized" } } +} diff --git a/gcc/testsuite/g++.dg/ext/attr-nonnull.C b/gcc/testsuite/g++.dg/ext/attr-nonnull.C new file mode 100644 index 00000000000..57d2cb025f9 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-nonnull.C @@ -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 +void __attribute__ ((nonnull (1))) +f (T*, T*, T*); + +template <> +void +f(int*, int*, int*); // { dg-warning "may be missing attributes" } + +template <> +void __attribute__ ((nonnull (3))) +f(float*, float*, float*); + + +void test_nonnull (void) +{ + f(0, 0, 0); // { dg-warning "null argument where non-null required \\\(argument 1\\\)" } + + f(0, 0, 0); // { dg-bogus "null argument" } + + f(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 } +} diff --git a/gcc/testsuite/g++.dg/ext/attr-noreturn-2.C b/gcc/testsuite/g++.dg/ext/attr-noreturn-2.C new file mode 100644 index 00000000000..cf70ba11349 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-noreturn-2.C @@ -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" } } +} diff --git a/gcc/testsuite/g++.dg/ext/attr-noreturn.C b/gcc/testsuite/g++.dg/ext/attr-noreturn.C new file mode 100644 index 00000000000..7d053d81af6 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-noreturn.C @@ -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 int __attribute__ ((noreturn)) f (); +template <> int f(); + +// Explicit specialization is noreturn but primary is not. +template int g (); +template <> int __attribute__ ((noreturn)) g(); + +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() + f(); +} // expect no -Wreturn-type warning here + +int test_noreturn (int) +{ + // Call should be retained. + f(); +} // expect no -Wreturn-type warning here + +int test_special_return (int) +{ + // Both calls must be emitted. + int val = f() + f(); + (void)&val; +} // { dg-warning "no return statement in function returning non-void" } + + +int test_primary_return (void) +{ + int val = g() + g(); + (void)&val; +} // { dg-warning "no return statement in function returning non-void" } + + +int test_special_noreturn (int, long) +{ + g(); +} // expect no -Wreturn-type warning here + + +// Verify that the call to f() above is eliminated but the call +// to f() and the two calls to f() are retained. +// { dg-final { scan-tree-dump-not "f" "optimized" } } +// { dg-final { scan-tree-dump-times "f" 2 "optimized" } } + +// Verify that the second call to f() 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 \\(\\);\[\n\r \]+__builtin_unreachable" 1 "optimized" } } + + +// Verify that the call to g() above is eliminated but the call +// to g() and to g() are both retained. +// { dg-final { scan-tree-dump-not "g" "optimized" } } +// { dg-final { scan-tree-dump-times "g" 1 "optimized" } } +// { dg-final { scan-tree-dump-times "g" 1 "optimized" } } + +// Verify that the call to g() 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 *\\(\\);\[\n\r \]+__builtin_unreachable" 1 "optimized" } } +// Verify that the call to g() 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 *\\(\\);\[\n\r \]+__builtin_unreachable" 0 "optimized" } } diff --git a/gcc/testsuite/g++.dg/ext/attr-nothrow-2.C b/gcc/testsuite/g++.dg/ext/attr-nothrow-2.C new file mode 100644 index 00000000000..8f1d7af7d06 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-nothrow-2.C @@ -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" } } diff --git a/gcc/testsuite/g++.dg/ext/attr-nothrow.C b/gcc/testsuite/g++.dg/ext/attr-nothrow.C new file mode 100644 index 00000000000..1d3d7153b8d --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-nothrow.C @@ -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 +void __attribute__ ((nothrow)) +f (); + +template <> +void f(); + +void f_void_nothrow (); +void f_int_maythrow (); + +void fv (void) +{ + try + { + f(); + } + catch (...) // cannot be be reached + { + f_void_nothrow (); // should be eliminated + } +} + + +void fi (void) +{ + try + { + f(); + } + 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" } } diff --git a/gcc/testsuite/g++.dg/ext/attr-optimize.C b/gcc/testsuite/g++.dg/ext/attr-optimize.C new file mode 100644 index 00000000000..481cf3f590c --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-optimize.C @@ -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 +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() +{ + // 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(); + // { dg-final { scan-tree-dump-times "foptimize_none_primary_failed *\\(\\)" 1 "optimized" } } +} + +void test_special () +{ + // Should be eliminated. + foptimize_none(); +// { dg-final { scan-tree-dump-not "foptimize_none_special_failed *\\(\\)" "optimized" } } +} + +// { dg-final { scan-tree-dump-times "__builtin_snprintf" 1 "optimized" } } diff --git a/gcc/testsuite/g++.dg/ext/attr-pure.C b/gcc/testsuite/g++.dg/ext/attr-pure.C new file mode 100644 index 00000000000..af36a31d6d5 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-pure.C @@ -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 +int __attribute__ ((pure)) fpure_none (T); + +template +int fpure_none (T); + +void template_pure_none () +{ + int i0 = fpure_none (0); + int i1 = fpure_none (0); + if (i0 != i1) + test_pure_none_failed (); + + // { dg-final { scan-tree-dump-not "test_pure_none_failed" "optimized" } } +} + + +template +int fnone_pure (T); + +template +int __attribute__ ((pure)) fnone_pure (T); + +void test_fnone_pure () +{ + int i0 = fnone_pure (0); + int i1 = fnone_pure (0); + if (i0 != i1) + test_none_pure_failed (); + + // { dg-final { scan-tree-dump-not "test_none_pure_failed" "optimized" } } +} diff --git a/gcc/testsuite/g++.dg/ext/attr-returns-nonnull.C b/gcc/testsuite/g++.dg/ext/attr-returns-nonnull.C new file mode 100644 index 00000000000..f75f32e46e8 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-returns-nonnull.C @@ -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 +void* __attribute__ ((returns_nonnull)) +g (); + +template <> +void* +g(); + +extern void g_void_returns_nonnull (); +extern void g_int_may_return_null (); + +void test_returns_nonnull () +{ + void *p = g(); + if (!p) + g_void_returns_nonnull (); + + (void)&p; +} + +void test_may_return_null () +{ + void *p = g(); + 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" } } diff --git a/gcc/testsuite/g++.dg/ext/attr-warning.C b/gcc/testsuite/g++.dg/ext/attr-warning.C new file mode 100644 index 00000000000..8369bac51d9 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-warning.C @@ -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 +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 (); + +void use_primary_before_warning () +{ + // Verify that uses of the primary are not diagnosed. + fwarn_primary(); + fwarn_primary(); +} + +// Redeclare the primary with attribute warning. +template +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 (); + +void use_primary_after_warning () +{ + // Verify that uses of the redeclared primary are diagnosed. + fwarn_primary(); // { dg-warning "primary" } + fwarn_primary(); // { dg-warning "primary" } +} + +void use_special () +{ + // Verify that the use of the specializatoin is not diagnosed. + fwarn_primary(); +}