mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-02-14 04:09:38 +08:00
re PR c++/65046 (-Wabi-tag doesn't warn about variables or function return types)
PR c++/65046 Automatically propagate ABI tags to variables and functions from their (return) type. * class.c (check_tag): Handle variables and functions. (mark_or_check_attr_tags): Split out from find_abi_tags_r. (mark_or_check_tags): Likewise. (mark_abi_tags): Use it. Rename from mark_type_abi_tags. (check_abi_tags): Add single argument overload for decls. Handle inheriting tags for decls. * mangle.c (write_mangled_name): Call it. (mangle_return_type_p): Split out from write_encoding. (unmangled_name_p): Split out from write_mangled_name. (write_mangled_name): Ignore abi_tag on namespace. * cp-tree.h (NAMESPACE_IS_INLINE): Replace NAMESPACE_ABI_TAG. * parser.c (cp_parser_namespace_definition): Set it. * name-lookup.c (handle_namespace_attrs): Use arguments. Warn about abi_tag attribute on non-inline namespace. * tree.c (check_abi_tag_args): Split out from handle_abi_tag_attribute. (handle_abi_tag_attribute): Allow tags on variables. From-SVN: r221521
This commit is contained in:
parent
9b65e171ed
commit
7cb7357360
@ -1,3 +1,25 @@
|
||||
2015-03-19 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/65046
|
||||
Automatically propagate ABI tags to variables and functions
|
||||
from their (return) type.
|
||||
* class.c (check_tag): Handle variables and functions.
|
||||
(mark_or_check_attr_tags): Split out from find_abi_tags_r.
|
||||
(mark_or_check_tags): Likewise.
|
||||
(mark_abi_tags): Use it. Rename from mark_type_abi_tags.
|
||||
(check_abi_tags): Add single argument overload for decls.
|
||||
Handle inheriting tags for decls.
|
||||
* mangle.c (write_mangled_name): Call it.
|
||||
(mangle_return_type_p): Split out from write_encoding.
|
||||
(unmangled_name_p): Split out from write_mangled_name.
|
||||
(write_mangled_name): Ignore abi_tag on namespace.
|
||||
* cp-tree.h (NAMESPACE_IS_INLINE): Replace NAMESPACE_ABI_TAG.
|
||||
* parser.c (cp_parser_namespace_definition): Set it.
|
||||
* name-lookup.c (handle_namespace_attrs): Use arguments. Warn
|
||||
about abi_tag attribute on non-inline namespace.
|
||||
* tree.c (check_abi_tag_args): Split out from handle_abi_tag_attribute.
|
||||
(handle_abi_tag_attribute): Allow tags on variables.
|
||||
|
||||
2015-03-19 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* decl2.c (cplus_decl_attributes): Also add "omp declare target"
|
||||
|
213
gcc/cp/class.c
213
gcc/cp/class.c
@ -1382,44 +1382,53 @@ struct abi_tag_data
|
||||
a tag NAMESPACE_DECL) or a STRING_CST (a tag attribute). */
|
||||
|
||||
static void
|
||||
check_tag (tree tag, tree *tp, abi_tag_data *p)
|
||||
check_tag (tree tag, tree id, tree *tp, abi_tag_data *p)
|
||||
{
|
||||
tree id;
|
||||
|
||||
if (TREE_CODE (tag) == STRING_CST)
|
||||
id = get_identifier (TREE_STRING_POINTER (tag));
|
||||
else
|
||||
{
|
||||
id = tag;
|
||||
tag = NULL_TREE;
|
||||
}
|
||||
|
||||
if (!IDENTIFIER_MARKED (id))
|
||||
{
|
||||
if (!tag)
|
||||
tag = build_string (IDENTIFIER_LENGTH (id) + 1,
|
||||
IDENTIFIER_POINTER (id));
|
||||
if (p->tags != error_mark_node)
|
||||
{
|
||||
/* We're collecting tags from template arguments. */
|
||||
/* We're collecting tags from template arguments or from
|
||||
the type of a variable or function return type. */
|
||||
p->tags = tree_cons (NULL_TREE, tag, p->tags);
|
||||
ABI_TAG_IMPLICIT (p->tags) = true;
|
||||
|
||||
/* Don't inherit this tag multiple times. */
|
||||
IDENTIFIER_MARKED (id) = true;
|
||||
|
||||
if (TYPE_P (p->t))
|
||||
{
|
||||
/* Tags inherited from type template arguments are only used
|
||||
to avoid warnings. */
|
||||
ABI_TAG_IMPLICIT (p->tags) = true;
|
||||
return;
|
||||
}
|
||||
/* For functions and variables we want to warn, too. */
|
||||
}
|
||||
|
||||
/* Otherwise we're diagnosing missing tags. */
|
||||
if (TREE_CODE (p->t) == FUNCTION_DECL)
|
||||
{
|
||||
if (warning (OPT_Wabi_tag, "%qD inherits the %E ABI tag "
|
||||
"that %qT (used in its return type) has",
|
||||
p->t, tag, *tp))
|
||||
inform (location_of (*tp), "%qT declared here", *tp);
|
||||
}
|
||||
else if (TREE_CODE (p->t) == VAR_DECL)
|
||||
{
|
||||
if (warning (OPT_Wabi_tag, "%qD inherits the %E ABI tag "
|
||||
"that %qT (used in its type) has", p->t, tag, *tp))
|
||||
inform (location_of (*tp), "%qT declared here", *tp);
|
||||
}
|
||||
else if (TYPE_P (p->subob))
|
||||
{
|
||||
if (warning (OPT_Wabi_tag, "%qT does not have the %E abi tag "
|
||||
if (warning (OPT_Wabi_tag, "%qT does not have the %E ABI tag "
|
||||
"that base %qT has", p->t, tag, p->subob))
|
||||
inform (location_of (p->subob), "%qT declared here",
|
||||
p->subob);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (warning (OPT_Wabi_tag, "%qT does not have the %E abi tag "
|
||||
if (warning (OPT_Wabi_tag, "%qT does not have the %E ABI tag "
|
||||
"that %qT (used in the type of %qD) has",
|
||||
p->t, tag, *tp, p->subob))
|
||||
{
|
||||
@ -1431,8 +1440,53 @@ check_tag (tree tag, tree *tp, abi_tag_data *p)
|
||||
}
|
||||
}
|
||||
|
||||
/* Find all the ABI tags in the attribute list ATTR and either call
|
||||
check_tag (if TP is non-null) or set IDENTIFIER_MARKED to val. */
|
||||
|
||||
static void
|
||||
mark_or_check_attr_tags (tree attr, tree *tp, abi_tag_data *p, bool val)
|
||||
{
|
||||
if (!attr)
|
||||
return;
|
||||
for (; (attr = lookup_attribute ("abi_tag", attr));
|
||||
attr = TREE_CHAIN (attr))
|
||||
for (tree list = TREE_VALUE (attr); list;
|
||||
list = TREE_CHAIN (list))
|
||||
{
|
||||
tree tag = TREE_VALUE (list);
|
||||
tree id = get_identifier (TREE_STRING_POINTER (tag));
|
||||
if (tp)
|
||||
check_tag (tag, id, tp, p);
|
||||
else
|
||||
IDENTIFIER_MARKED (id) = val;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find all the ABI tags on T and its enclosing scopes and either call
|
||||
check_tag (if TP is non-null) or set IDENTIFIER_MARKED to val. */
|
||||
|
||||
static void
|
||||
mark_or_check_tags (tree t, tree *tp, abi_tag_data *p, bool val)
|
||||
{
|
||||
while (t != global_namespace)
|
||||
{
|
||||
tree attr;
|
||||
if (TYPE_P (t))
|
||||
{
|
||||
attr = TYPE_ATTRIBUTES (t);
|
||||
t = CP_TYPE_CONTEXT (t);
|
||||
}
|
||||
else
|
||||
{
|
||||
attr = DECL_ATTRIBUTES (t);
|
||||
t = CP_DECL_CONTEXT (t);
|
||||
}
|
||||
mark_or_check_attr_tags (attr, tp, p, val);
|
||||
}
|
||||
}
|
||||
|
||||
/* walk_tree callback for check_abi_tags: if the type at *TP involves any
|
||||
types with abi tags, add the corresponding identifiers to the VEC in
|
||||
types with ABI tags, add the corresponding identifiers to the VEC in
|
||||
*DATA and set IDENTIFIER_MARKED. */
|
||||
|
||||
static tree
|
||||
@ -1447,63 +1501,112 @@ find_abi_tags_r (tree *tp, int *walk_subtrees, void *data)
|
||||
|
||||
abi_tag_data *p = static_cast<struct abi_tag_data*>(data);
|
||||
|
||||
for (tree ns = decl_namespace_context (*tp);
|
||||
ns != global_namespace;
|
||||
ns = CP_DECL_CONTEXT (ns))
|
||||
if (NAMESPACE_ABI_TAG (ns))
|
||||
check_tag (DECL_NAME (ns), tp, p);
|
||||
mark_or_check_tags (*tp, tp, p, false);
|
||||
|
||||
if (tree attributes = lookup_attribute ("abi_tag", TYPE_ATTRIBUTES (*tp)))
|
||||
{
|
||||
for (tree list = TREE_VALUE (attributes); list;
|
||||
list = TREE_CHAIN (list))
|
||||
{
|
||||
tree tag = TREE_VALUE (list);
|
||||
check_tag (tag, tp, p);
|
||||
}
|
||||
}
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Set IDENTIFIER_MARKED on all the ABI tags on T and its (transitively
|
||||
complete) template arguments. */
|
||||
/* walk_tree callback for mark_abi_tags: if *TP is a class, set
|
||||
IDENTIFIER_MARKED on its ABI tags. */
|
||||
|
||||
static tree
|
||||
mark_abi_tags_r (tree *tp, int *walk_subtrees, void *data)
|
||||
{
|
||||
if (!OVERLOAD_TYPE_P (*tp))
|
||||
return NULL_TREE;
|
||||
|
||||
/* walk_tree shouldn't be walking into any subtrees of a RECORD_TYPE
|
||||
anyway, but let's make sure of it. */
|
||||
*walk_subtrees = false;
|
||||
|
||||
bool *valp = static_cast<bool*>(data);
|
||||
|
||||
mark_or_check_tags (*tp, NULL, NULL, *valp);
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Set IDENTIFIER_MARKED on all the ABI tags on T and its enclosing
|
||||
scopes. */
|
||||
|
||||
static void
|
||||
mark_type_abi_tags (tree t, bool val)
|
||||
mark_abi_tags (tree t, bool val)
|
||||
{
|
||||
for (tree ns = decl_namespace_context (t);
|
||||
ns != global_namespace;
|
||||
ns = CP_DECL_CONTEXT (ns))
|
||||
if (NAMESPACE_ABI_TAG (ns))
|
||||
IDENTIFIER_MARKED (DECL_NAME (ns)) = val;
|
||||
|
||||
tree attributes = lookup_attribute ("abi_tag", TYPE_ATTRIBUTES (t));
|
||||
if (attributes)
|
||||
mark_or_check_tags (t, NULL, NULL, val);
|
||||
if (DECL_P (t))
|
||||
{
|
||||
for (tree list = TREE_VALUE (attributes); list;
|
||||
list = TREE_CHAIN (list))
|
||||
if (DECL_LANG_SPECIFIC (t) && DECL_USE_TEMPLATE (t)
|
||||
&& PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t)))
|
||||
{
|
||||
tree tag = TREE_VALUE (list);
|
||||
tree id = get_identifier (TREE_STRING_POINTER (tag));
|
||||
IDENTIFIER_MARKED (id) = val;
|
||||
/* Template arguments are part of the signature. */
|
||||
tree level = INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (t));
|
||||
for (int j = 0; j < TREE_VEC_LENGTH (level); ++j)
|
||||
{
|
||||
tree arg = TREE_VEC_ELT (level, j);
|
||||
cp_walk_tree_without_duplicates (&arg, mark_abi_tags_r, &val);
|
||||
}
|
||||
}
|
||||
if (TREE_CODE (t) == FUNCTION_DECL)
|
||||
/* A function's parameter types are part of the signature, so
|
||||
we don't need to inherit any tags that are also in them. */
|
||||
for (tree arg = FUNCTION_FIRST_USER_PARMTYPE (t); arg;
|
||||
arg = TREE_CHAIN (arg))
|
||||
cp_walk_tree_without_duplicates (&TREE_VALUE (arg),
|
||||
mark_abi_tags_r, &val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that class T has all the abi tags that subobject SUBOB has, or
|
||||
warn if not. */
|
||||
/* Check that T has all the ABI tags that subobject SUBOB has, or
|
||||
warn if not. If T is a (variable or function) declaration, also
|
||||
add any missing tags. */
|
||||
|
||||
static void
|
||||
check_abi_tags (tree t, tree subob)
|
||||
{
|
||||
mark_type_abi_tags (t, true);
|
||||
bool inherit = DECL_P (t);
|
||||
|
||||
if (!inherit && !warn_abi_tag)
|
||||
return;
|
||||
|
||||
tree decl = TYPE_P (t) ? TYPE_NAME (t) : t;
|
||||
if (!TREE_PUBLIC (decl))
|
||||
/* No need to worry about things local to this TU. */
|
||||
return;
|
||||
|
||||
mark_abi_tags (t, true);
|
||||
|
||||
tree subtype = TYPE_P (subob) ? subob : TREE_TYPE (subob);
|
||||
struct abi_tag_data data = { t, subob, error_mark_node };
|
||||
if (inherit)
|
||||
data.tags = NULL_TREE;
|
||||
|
||||
cp_walk_tree_without_duplicates (&subtype, find_abi_tags_r, &data);
|
||||
|
||||
mark_type_abi_tags (t, false);
|
||||
if (inherit && data.tags)
|
||||
{
|
||||
tree attr = lookup_attribute ("abi_tag", DECL_ATTRIBUTES (t));
|
||||
if (attr)
|
||||
TREE_VALUE (attr) = chainon (data.tags, TREE_VALUE (attr));
|
||||
else
|
||||
DECL_ATTRIBUTES (t)
|
||||
= tree_cons (get_identifier ("abi_tag"), data.tags,
|
||||
DECL_ATTRIBUTES (t));
|
||||
}
|
||||
|
||||
mark_abi_tags (t, false);
|
||||
}
|
||||
|
||||
/* Check that DECL has all the ABI tags that are used in parts of its type
|
||||
that are not reflected in its mangled name. */
|
||||
|
||||
void
|
||||
check_abi_tags (tree decl)
|
||||
{
|
||||
if (TREE_CODE (decl) == VAR_DECL)
|
||||
check_abi_tags (decl, TREE_TYPE (decl));
|
||||
else if (TREE_CODE (decl) == FUNCTION_DECL
|
||||
&& !mangle_return_type_p (decl))
|
||||
check_abi_tags (decl, TREE_TYPE (TREE_TYPE (decl)));
|
||||
}
|
||||
|
||||
void
|
||||
@ -1513,7 +1616,7 @@ inherit_targ_abi_tags (tree t)
|
||||
|| CLASSTYPE_TEMPLATE_INFO (t) == NULL_TREE)
|
||||
return;
|
||||
|
||||
mark_type_abi_tags (t, true);
|
||||
mark_abi_tags (t, true);
|
||||
|
||||
tree args = CLASSTYPE_TI_ARGS (t);
|
||||
struct abi_tag_data data = { t, NULL_TREE, NULL_TREE };
|
||||
@ -1541,7 +1644,7 @@ inherit_targ_abi_tags (tree t)
|
||||
TYPE_ATTRIBUTES (t));
|
||||
}
|
||||
|
||||
mark_type_abi_tags (t, false);
|
||||
mark_abi_tags (t, false);
|
||||
}
|
||||
|
||||
/* Return true, iff class T has a non-virtual destructor that is
|
||||
|
@ -152,7 +152,7 @@ c-common.h, not after.
|
||||
DECL_MUTABLE_P (in FIELD_DECL)
|
||||
DECL_DEPENDENT_P (in USING_DECL)
|
||||
LABEL_DECL_BREAK (in LABEL_DECL)
|
||||
NAMESPACE_ABI_TAG (in NAMESPACE_DECL)
|
||||
NAMESPACE_IS_INLINE (in NAMESPACE_DECL)
|
||||
1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
|
||||
DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
|
||||
DECL_MEMBER_TEMPLATE_P (in TEMPLATE_DECL)
|
||||
@ -2657,9 +2657,8 @@ struct GTY(()) lang_decl {
|
||||
#define LOCAL_CLASS_P(NODE) \
|
||||
(decl_function_context (TYPE_MAIN_DECL (NODE)) != NULL_TREE)
|
||||
|
||||
/* 1 iff this NAMESPACE_DECL should also be treated as an ABI tag for
|
||||
-Wabi-tag. */
|
||||
#define NAMESPACE_ABI_TAG(NODE) \
|
||||
/* 1 iff this NAMESPACE_DECL is an inline namespace. */
|
||||
#define NAMESPACE_IS_INLINE(NODE) \
|
||||
DECL_LANG_FLAG_0 (NAMESPACE_DECL_CHECK (NODE))
|
||||
|
||||
/* For a NAMESPACE_DECL: the list of using namespace directives
|
||||
@ -5311,6 +5310,7 @@ extern void explain_non_literal_class (tree);
|
||||
extern void inherit_targ_abi_tags (tree);
|
||||
extern void defaulted_late_check (tree);
|
||||
extern bool defaultable_fn_check (tree);
|
||||
extern void check_abi_tags (tree);
|
||||
extern void fixup_type_variants (tree);
|
||||
extern void fixup_attribute_variants (tree);
|
||||
extern tree* decl_cloned_function_p (const_tree, bool);
|
||||
@ -6069,6 +6069,7 @@ extern bool type_has_nontrivial_copy_init (const_tree);
|
||||
extern bool class_tmpl_impl_spec_p (const_tree);
|
||||
extern int zero_init_p (const_tree);
|
||||
extern bool check_abi_tag_redeclaration (const_tree, const_tree, const_tree);
|
||||
extern bool check_abi_tag_args (tree, tree);
|
||||
extern tree strip_typedefs (tree);
|
||||
extern tree strip_typedefs_expr (tree);
|
||||
extern tree copy_binfo (tree, tree, tree,
|
||||
@ -6345,6 +6346,7 @@ extern tree mangle_tls_wrapper_fn (tree);
|
||||
extern bool decl_tls_wrapper_p (tree);
|
||||
extern tree mangle_ref_init_variable (tree);
|
||||
extern char * get_mangled_vtable_map_var_name (tree);
|
||||
extern bool mangle_return_type_p (tree);
|
||||
|
||||
/* in dump.c */
|
||||
extern bool cp_dump_tree (void *, tree);
|
||||
|
@ -648,6 +648,48 @@ find_substitution (tree node)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Returns whether DECL's symbol name should be the plain unqualified-id
|
||||
rather than a more complicated mangled name. */
|
||||
|
||||
static bool
|
||||
unmangled_name_p (const tree decl)
|
||||
{
|
||||
if (TREE_CODE (decl) == FUNCTION_DECL)
|
||||
{
|
||||
/* The names of `extern "C"' functions are not mangled. */
|
||||
return (DECL_EXTERN_C_FUNCTION_P (decl)
|
||||
/* But overloaded operator names *are* mangled. */
|
||||
&& !DECL_OVERLOADED_OPERATOR_P (decl));
|
||||
}
|
||||
else if (VAR_P (decl))
|
||||
{
|
||||
/* static variables are mangled. */
|
||||
if (!DECL_EXTERNAL_LINKAGE_P (decl))
|
||||
return false;
|
||||
|
||||
/* extern "C" declarations aren't mangled. */
|
||||
if (DECL_EXTERN_C_P (decl))
|
||||
return true;
|
||||
|
||||
/* Other variables at non-global scope are mangled. */
|
||||
if (CP_DECL_CONTEXT (decl) != global_namespace)
|
||||
return false;
|
||||
|
||||
/* Variable template instantiations are mangled. */
|
||||
if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
|
||||
&& variable_template_p (DECL_TI_TEMPLATE (decl)))
|
||||
return false;
|
||||
|
||||
/* Declarations with ABI tags are mangled. */
|
||||
if (lookup_attribute ("abi_tag", DECL_ATTRIBUTES (decl)))
|
||||
return false;
|
||||
|
||||
/* The names of non-static global variables aren't mangled. */
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TOP_LEVEL is true, if this is being called at outermost level of
|
||||
mangling. It should be false when mangling a decl appearing in an
|
||||
@ -660,13 +702,10 @@ write_mangled_name (const tree decl, bool top_level)
|
||||
{
|
||||
MANGLE_TRACE_TREE ("mangled-name", decl);
|
||||
|
||||
if (/* The names of `extern "C"' functions are not mangled. */
|
||||
DECL_EXTERN_C_FUNCTION_P (decl)
|
||||
/* But overloaded operator names *are* mangled. */
|
||||
&& !DECL_OVERLOADED_OPERATOR_P (decl))
|
||||
{
|
||||
unmangled_name:;
|
||||
check_abi_tags (decl);
|
||||
|
||||
if (unmangled_name_p (decl))
|
||||
{
|
||||
if (top_level)
|
||||
write_string (IDENTIFIER_POINTER (DECL_NAME (decl)));
|
||||
else
|
||||
@ -680,18 +719,6 @@ write_mangled_name (const tree decl, bool top_level)
|
||||
write_source_name (DECL_NAME (decl));
|
||||
}
|
||||
}
|
||||
else if (VAR_P (decl)
|
||||
/* Variable template instantiations are mangled. */
|
||||
&& !(DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
|
||||
&& variable_template_p (DECL_TI_TEMPLATE (decl)))
|
||||
/* The names of non-static global variables aren't mangled. */
|
||||
&& DECL_EXTERNAL_LINKAGE_P (decl)
|
||||
&& (CP_DECL_CONTEXT (decl) == global_namespace
|
||||
/* And neither are `extern "C"' variables. */
|
||||
|| DECL_EXTERN_C_P (decl)))
|
||||
{
|
||||
goto unmangled_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_string ("_Z");
|
||||
@ -699,6 +726,18 @@ write_mangled_name (const tree decl, bool top_level)
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true if the return type of DECL is part of its signature, and
|
||||
therefore its mangling. */
|
||||
|
||||
bool
|
||||
mangle_return_type_p (tree decl)
|
||||
{
|
||||
return (!DECL_CONSTRUCTOR_P (decl)
|
||||
&& !DECL_DESTRUCTOR_P (decl)
|
||||
&& !DECL_CONV_FN_P (decl)
|
||||
&& decl_is_template_id (decl, NULL));
|
||||
}
|
||||
|
||||
/* <encoding> ::= <function name> <bare-function-type>
|
||||
::= <data name> */
|
||||
|
||||
@ -740,10 +779,7 @@ write_encoding (const tree decl)
|
||||
}
|
||||
|
||||
write_bare_function_type (fn_type,
|
||||
(!DECL_CONSTRUCTOR_P (decl)
|
||||
&& !DECL_DESTRUCTOR_P (decl)
|
||||
&& !DECL_CONV_FN_P (decl)
|
||||
&& decl_is_template_id (decl, NULL)),
|
||||
mangle_return_type_p (decl),
|
||||
d);
|
||||
}
|
||||
}
|
||||
@ -1290,7 +1326,7 @@ write_unqualified_name (tree decl)
|
||||
if (tree tmpl = most_general_template (decl))
|
||||
decl = DECL_TEMPLATE_RESULT (tmpl);
|
||||
/* Don't crash on an unbound class template. */
|
||||
if (decl)
|
||||
if (decl && TREE_CODE (decl) != NAMESPACE_DECL)
|
||||
{
|
||||
tree attrs = (TREE_CODE (decl) == TYPE_DECL
|
||||
? TYPE_ATTRIBUTES (TREE_TYPE (decl))
|
||||
|
@ -3657,7 +3657,24 @@ handle_namespace_attrs (tree ns, tree attributes)
|
||||
}
|
||||
else if (is_attribute_p ("abi_tag", name))
|
||||
{
|
||||
NAMESPACE_ABI_TAG (ns) = true;
|
||||
if (!NAMESPACE_IS_INLINE (ns))
|
||||
{
|
||||
warning (OPT_Wattributes, "ignoring %qD attribute on non-inline "
|
||||
"namespace", name);
|
||||
continue;
|
||||
}
|
||||
if (!args)
|
||||
{
|
||||
tree dn = DECL_NAME (ns);
|
||||
args = build_string (IDENTIFIER_LENGTH (dn) + 1,
|
||||
IDENTIFIER_POINTER (dn));
|
||||
TREE_TYPE (args) = char_array_type_node;
|
||||
args = fix_string_type (args);
|
||||
args = build_tree_list (NULL_TREE, args);
|
||||
}
|
||||
if (check_abi_tag_args (args, name))
|
||||
DECL_ATTRIBUTES (ns) = tree_cons (name, args,
|
||||
DECL_ATTRIBUTES (ns));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -16233,6 +16233,7 @@ cp_parser_namespace_definition (cp_parser* parser)
|
||||
if (is_inline)
|
||||
{
|
||||
tree name_space = current_namespace;
|
||||
NAMESPACE_IS_INLINE (name_space) = true;
|
||||
/* Set up namespace association. */
|
||||
DECL_NAMESPACE_ASSOCIATIONS (name_space)
|
||||
= tree_cons (CP_DECL_CONTEXT (name_space), NULL_TREE,
|
||||
|
@ -3485,13 +3485,17 @@ check_abi_tag_redeclaration (const_tree decl, const_tree old, const_tree new_)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Handle an "abi_tag" attribute; arguments as in
|
||||
struct attribute_spec.handler. */
|
||||
/* The abi_tag attribute with the name NAME was given ARGS. If they are
|
||||
ill-formed, give an error and return false; otherwise, return true. */
|
||||
|
||||
static tree
|
||||
handle_abi_tag_attribute (tree* node, tree name, tree args,
|
||||
int flags, bool* no_add_attrs)
|
||||
bool
|
||||
check_abi_tag_args (tree args, tree name)
|
||||
{
|
||||
if (!args)
|
||||
{
|
||||
error ("the %qE attribute requires arguments", name);
|
||||
return false;
|
||||
}
|
||||
for (tree arg = args; arg; arg = TREE_CHAIN (arg))
|
||||
{
|
||||
tree elt = TREE_VALUE (arg);
|
||||
@ -3502,7 +3506,7 @@ handle_abi_tag_attribute (tree* node, tree name, tree args,
|
||||
{
|
||||
error ("arguments to the %qE attribute must be narrow string "
|
||||
"literals", name);
|
||||
goto fail;
|
||||
return false;
|
||||
}
|
||||
const char *begin = TREE_STRING_POINTER (elt);
|
||||
const char *end = begin + TREE_STRING_LENGTH (elt);
|
||||
@ -3517,7 +3521,7 @@ handle_abi_tag_attribute (tree* node, tree name, tree args,
|
||||
"identifiers", name);
|
||||
inform (input_location, "%<%c%> is not a valid first "
|
||||
"character for an identifier", c);
|
||||
goto fail;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (p == end - 1)
|
||||
@ -3530,11 +3534,23 @@ handle_abi_tag_attribute (tree* node, tree name, tree args,
|
||||
"identifiers", name);
|
||||
inform (input_location, "%<%c%> is not a valid character "
|
||||
"in an identifier", c);
|
||||
goto fail;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Handle an "abi_tag" attribute; arguments as in
|
||||
struct attribute_spec.handler. */
|
||||
|
||||
static tree
|
||||
handle_abi_tag_attribute (tree* node, tree name, tree args,
|
||||
int flags, bool* no_add_attrs)
|
||||
{
|
||||
if (!check_abi_tag_args (args, name))
|
||||
goto fail;
|
||||
|
||||
if (TYPE_P (*node))
|
||||
{
|
||||
@ -3578,14 +3594,16 @@ handle_abi_tag_attribute (tree* node, tree name, tree args,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TREE_CODE (*node) != FUNCTION_DECL)
|
||||
if (TREE_CODE (*node) != FUNCTION_DECL
|
||||
&& TREE_CODE (*node) != VAR_DECL)
|
||||
{
|
||||
error ("%qE attribute applied to non-function %qD", name, *node);
|
||||
error ("%qE attribute applied to non-function, non-variable %qD",
|
||||
name, *node);
|
||||
goto fail;
|
||||
}
|
||||
else if (DECL_LANGUAGE (*node) == lang_c)
|
||||
{
|
||||
error ("%qE attribute applied to extern \"C\" function %qD",
|
||||
error ("%qE attribute applied to extern \"C\" declaration %qD",
|
||||
name, *node);
|
||||
goto fail;
|
||||
}
|
||||
|
@ -18722,18 +18722,26 @@ Some attributes only make sense for C++ programs.
|
||||
@table @code
|
||||
@item abi_tag ("@var{tag}", ...)
|
||||
@cindex @code{abi_tag} attribute
|
||||
The @code{abi_tag} attribute can be applied to a function or class
|
||||
declaration. It modifies the mangled name of the function or class to
|
||||
The @code{abi_tag} attribute can be applied to a function, variable, or class
|
||||
declaration. It modifies the mangled name of the entity to
|
||||
incorporate the tag name, in order to distinguish the function or
|
||||
class from an earlier version with a different ABI; perhaps the class
|
||||
has changed size, or the function has a different return type that is
|
||||
not encoded in the mangled name.
|
||||
|
||||
The attribute can also be applied to an inline namespace, but does not
|
||||
affect the mangled name of the namespace; in this case it is only used
|
||||
for @option{-Wabi-tag} warnings and automatic tagging of functions and
|
||||
variables. Tagging inline namespaces is generally preferable to
|
||||
tagging individual declarations, but the latter is sometimes
|
||||
necessary, such as when only certain members of a class need to be
|
||||
tagged.
|
||||
|
||||
The argument can be a list of strings of arbitrary length. The
|
||||
strings are sorted on output, so the order of the list is
|
||||
unimportant.
|
||||
|
||||
A redeclaration of a function or class must not add new ABI tags,
|
||||
A redeclaration of an entity must not add new ABI tags,
|
||||
since doing so would change the mangled name.
|
||||
|
||||
The ABI tags apply to a name, so all instantiations and
|
||||
@ -18745,6 +18753,13 @@ not have all the ABI tags used by its subobjects and virtual functions; for user
|
||||
that needs to coexist with an earlier ABI, using this option can help
|
||||
to find all affected types that need to be tagged.
|
||||
|
||||
When a type involving an ABI tag is used as the type of a variable or
|
||||
return type of a function where that tag is not already present in the
|
||||
signature of the function, the tag is automatically applied to the
|
||||
variable or function. @option{-Wabi-tag} also warns about this
|
||||
situation; this warning can be avoided by explicitly tagging the
|
||||
variable or function or moving it into a tagged inline namespace.
|
||||
|
||||
@item init_priority (@var{priority})
|
||||
@cindex @code{init_priority} attribute
|
||||
|
||||
|
@ -197,7 +197,7 @@ in the following sections.
|
||||
-fvtv-counts -fvtv-debug @gol
|
||||
-fvisibility-ms-compat @gol
|
||||
-fext-numeric-literals @gol
|
||||
-Wabi=@var{n} -Wconversion-null -Wctor-dtor-privacy @gol
|
||||
-Wabi=@var{n} -Wabi-tag -Wconversion-null -Wctor-dtor-privacy @gol
|
||||
-Wdelete-non-virtual-dtor -Wliteral-suffix -Wnarrowing @gol
|
||||
-Wnoexcept -Wnon-virtual-dtor -Wreorder @gol
|
||||
-Weffc++ -Wstrict-null-sentinel @gol
|
||||
@ -2641,6 +2641,13 @@ union U @{
|
||||
|
||||
@end itemize
|
||||
|
||||
@item -Wabi-tag @r{(C++ and Objective-C++ only)}
|
||||
@opindex Wabi-tag
|
||||
@opindex -Wabi-tag
|
||||
Warn when a type with an ABI tag is used in a context that does not
|
||||
have that ABI tag. See @ref{C++ Attributes} for more information
|
||||
about ABI tags.
|
||||
|
||||
@item -Wctor-dtor-privacy @r{(C++ and Objective-C++ only)}
|
||||
@opindex Wctor-dtor-privacy
|
||||
@opindex Wno-ctor-dtor-privacy
|
||||
|
@ -5,8 +5,8 @@ void f(int) __attribute ((abi_tag ("foo","bar")));
|
||||
|
||||
struct __attribute ((abi_tag ("bar"))) A { };
|
||||
|
||||
struct B: A { }; // { dg-warning "bar. abi tag" }
|
||||
struct D { A* ap; }; // { dg-warning "bar. abi tag" }
|
||||
struct B: A { }; // { dg-warning "bar. ABI tag" }
|
||||
struct D { A* ap; }; // { dg-warning "bar. ABI tag" }
|
||||
|
||||
// { dg-final { scan-assembler "_Z1gB3baz1AB3bar" } }
|
||||
void g(A) __attribute ((abi_tag ("baz")));
|
||||
|
30
gcc/testsuite/g++.dg/abi/abi-tag14.C
Normal file
30
gcc/testsuite/g++.dg/abi/abi-tag14.C
Normal file
@ -0,0 +1,30 @@
|
||||
// { dg-options "-Wabi-tag" }
|
||||
|
||||
inline namespace __cxx11 __attribute ((abi_tag ("cxx11"))) {
|
||||
struct A {};
|
||||
};
|
||||
|
||||
// { dg-final { scan-assembler "_Z1aB5cxx11" } }
|
||||
A a; // { dg-warning "\"cxx11\"" }
|
||||
|
||||
// { dg-final { scan-assembler "_Z1fB5cxx11v" } }
|
||||
A f() {} // { dg-warning "\"cxx11\"" }
|
||||
|
||||
namespace {
|
||||
A a2;
|
||||
A f2() {}
|
||||
struct B: A {};
|
||||
}
|
||||
|
||||
// { dg-final { scan-assembler "_Z1fPN7__cxx111AE" } }
|
||||
A f(A*) {}
|
||||
|
||||
// { dg-final { scan-assembler "_Z1gIN7__cxx111AEET_v" } }
|
||||
template <class T> T g() { }
|
||||
template <> A g<A>() { }
|
||||
|
||||
// { dg-final { scan-assembler "_Z1vIN7__cxx111AEE" { target c++14 } } }
|
||||
#if __cplusplus >= 201402L
|
||||
template <class T> T v = T();
|
||||
void *p = &v<A>;
|
||||
#endif
|
@ -2,7 +2,7 @@
|
||||
|
||||
struct __attribute ((abi_tag ("X"))) A { };
|
||||
|
||||
struct B // { dg-warning "abi tag" }
|
||||
struct B // { dg-warning "ABI tag" }
|
||||
{
|
||||
virtual void f(A); // { dg-message "declared here" }
|
||||
};
|
||||
|
@ -4,6 +4,6 @@ template<class T>
|
||||
struct __attribute ((__abi_tag__("cxx11"))) list // { dg-message "list" }
|
||||
{ };
|
||||
|
||||
struct X { // { dg-warning "abi tag" }
|
||||
struct X { // { dg-warning "ABI tag" }
|
||||
list<int> l; // { dg-message "X::l" }
|
||||
};
|
||||
|
@ -1,3 +1,8 @@
|
||||
2015-03-19 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* config/locale/gnu/messages_members.cc: Revert abi-tag change.
|
||||
* src/c++11/cxx11-shim_facets.cc: Revert abi-tag change.
|
||||
|
||||
2015-03-18 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
PR c++/65046
|
||||
|
@ -46,8 +46,8 @@ namespace
|
||||
|
||||
typedef messages_base::catalog catalog;
|
||||
|
||||
struct _GLIBCXX_DEFAULT_ABI_TAG Catalog_info
|
||||
{
|
||||
struct Catalog_info
|
||||
{
|
||||
Catalog_info(catalog __id, const string& __domain, locale __loc)
|
||||
: _M_id(__id), _M_domain(__domain), _M_locale(__loc)
|
||||
{ }
|
||||
@ -57,7 +57,7 @@ namespace
|
||||
locale _M_locale;
|
||||
};
|
||||
|
||||
class _GLIBCXX_DEFAULT_ABI_TAG Catalogs
|
||||
class Catalogs
|
||||
{
|
||||
public:
|
||||
Catalogs() : _M_catalog_counter(0) { }
|
||||
@ -133,7 +133,6 @@ namespace
|
||||
std::vector<Catalog_info*> _M_infos;
|
||||
};
|
||||
|
||||
_GLIBCXX_DEFAULT_ABI_TAG
|
||||
Catalogs&
|
||||
get_catalogs()
|
||||
{
|
||||
|
@ -215,7 +215,7 @@ namespace std
|
||||
#if _GLIBCXX_USE_CXX11_ABI
|
||||
namespace std
|
||||
{
|
||||
inline namespace __cxx11 __attribute__((__abi_tag__)) { }
|
||||
inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { }
|
||||
}
|
||||
# define _GLIBCXX_NAMESPACE_CXX11 __cxx11::
|
||||
# define _GLIBCXX_BEGIN_NAMESPACE_CXX11 namespace __cxx11 {
|
||||
|
@ -227,8 +227,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
namespace // unnamed
|
||||
{
|
||||
template<typename _CharT>
|
||||
struct _GLIBCXX_DEFAULT_ABI_TAG numpunct_shim
|
||||
: std::numpunct<_CharT>, facet::__shim
|
||||
struct numpunct_shim : std::numpunct<_CharT>, facet::__shim
|
||||
{
|
||||
typedef typename numpunct<_CharT>::__cache_type __cache_type;
|
||||
|
||||
@ -252,8 +251,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
};
|
||||
|
||||
template<typename _CharT>
|
||||
struct _GLIBCXX_DEFAULT_ABI_TAG collate_shim
|
||||
: std::collate<_CharT>, facet::__shim
|
||||
struct collate_shim : std::collate<_CharT>, facet::__shim
|
||||
{
|
||||
typedef basic_string<_CharT> string_type;
|
||||
|
||||
@ -278,8 +276,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
};
|
||||
|
||||
template<typename _CharT>
|
||||
struct _GLIBCXX_DEFAULT_ABI_TAG time_get_shim
|
||||
: std::time_get<_CharT>, facet::__shim
|
||||
struct time_get_shim : std::time_get<_CharT>, facet::__shim
|
||||
{
|
||||
typedef typename std::time_get<_CharT>::iter_type iter_type;
|
||||
typedef typename std::time_get<_CharT>::char_type char_type;
|
||||
@ -333,8 +330,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
};
|
||||
|
||||
template<typename _CharT, bool _Intl>
|
||||
struct _GLIBCXX_DEFAULT_ABI_TAG moneypunct_shim
|
||||
: std::moneypunct<_CharT, _Intl>, facet::__shim
|
||||
struct moneypunct_shim : std::moneypunct<_CharT, _Intl>, facet::__shim
|
||||
{
|
||||
typedef typename moneypunct<_CharT, _Intl>::__cache_type __cache_type;
|
||||
|
||||
@ -361,8 +357,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
};
|
||||
|
||||
template<typename _CharT>
|
||||
struct _GLIBCXX_DEFAULT_ABI_TAG money_get_shim
|
||||
: std::money_get<_CharT>, facet::__shim
|
||||
struct money_get_shim : std::money_get<_CharT>, facet::__shim
|
||||
{
|
||||
typedef typename std::money_get<_CharT>::iter_type iter_type;
|
||||
typedef typename std::money_get<_CharT>::char_type char_type;
|
||||
@ -403,8 +398,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
};
|
||||
|
||||
template<typename _CharT>
|
||||
struct _GLIBCXX_DEFAULT_ABI_TAG money_put_shim
|
||||
: std::money_put<_CharT>, facet::__shim
|
||||
struct money_put_shim : std::money_put<_CharT>, facet::__shim
|
||||
{
|
||||
typedef typename std::money_put<_CharT>::iter_type iter_type;
|
||||
typedef typename std::money_put<_CharT>::char_type char_type;
|
||||
@ -433,8 +427,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
};
|
||||
|
||||
template<typename _CharT>
|
||||
struct _GLIBCXX_DEFAULT_ABI_TAG messages_shim
|
||||
: std::messages<_CharT>, facet::__shim
|
||||
struct messages_shim : std::messages<_CharT>, facet::__shim
|
||||
{
|
||||
typedef messages_base::catalog catalog;
|
||||
typedef basic_string<_CharT> string_type;
|
||||
|
Loading…
Reference in New Issue
Block a user