Skip to content

Commit

Permalink
PR c++/83871 - wrong code for attribute const and pure on distinct te…
Browse files Browse the repository at this point in the history
…mplate 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.



git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@258045 138bc75d-0d04-0410-961f-82ee72b054a4
  • Loading branch information
msebor committed Feb 27, 2018
1 parent f4e3e4b commit 7762840
Show file tree
Hide file tree
Showing 27 changed files with 1,404 additions and 38 deletions.
6 changes: 6 additions & 0 deletions gcc/ChangeLog
Original file line number Diff line number Diff line change
@@ -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
Expand Down
5 changes: 5 additions & 0 deletions gcc/c-family/ChangeLog
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
5 changes: 5 additions & 0 deletions gcc/c-family/c.opt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
;
Expand Down
11 changes: 11 additions & 0 deletions gcc/cp/ChangeLog
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
3 changes: 2 additions & 1 deletion gcc/cp/cp-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
105 changes: 74 additions & 31 deletions gcc/cp/decl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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))
{
Expand Down Expand Up @@ -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))
{
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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);
}
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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;

Expand Down
123 changes: 118 additions & 5 deletions gcc/cp/pt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 7762840

Please sign in to comment.