From: Jason Merrill Date: Thu, 19 Mar 2015 19:31:48 +0000 (-0400) Subject: re PR c++/65046 (-Wabi-tag doesn't warn about variables or function return types) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7cb73573606d5b0881b0af778a81b5b9c1569f36;p=gcc.git 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 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f8ebb2dcfa9..f90e447cc98 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,25 @@ +2015-03-19 Jason Merrill + + 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 * decl2.c (cplus_decl_attributes): Also add "omp declare target" diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 8612163711c..0518320d6b9 100644 --- a/gcc/cp/class.c +++ b/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(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 void -mark_type_abi_tags (tree t, bool val) +static tree +mark_abi_tags_r (tree *tp, int *walk_subtrees, void *data) { - 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; + 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(data); - tree attributes = lookup_attribute ("abi_tag", TYPE_ATTRIBUTES (t)); - if (attributes) + 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_abi_tags (tree t, bool val) +{ + 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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 65219f159e3..7111449da4b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index fbf4bf27c07..b0f72d1ff14 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -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)); +} + /* ::= ::= */ @@ -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)) diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index ba16befa74d..c845d521a53 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -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 { diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a18f38ce0af..98d741f440a 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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, diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index c8e6f0c796f..ef53aff87f7 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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; } diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 91b94f7b610..c6fdb2453c8 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -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 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index f2ab51744dc..133cca9042e 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 diff --git a/gcc/testsuite/g++.dg/abi/abi-tag1.C b/gcc/testsuite/g++.dg/abi/abi-tag1.C index 942929cdd35..d57ed87d803 100644 --- a/gcc/testsuite/g++.dg/abi/abi-tag1.C +++ b/gcc/testsuite/g++.dg/abi/abi-tag1.C @@ -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"))); diff --git a/gcc/testsuite/g++.dg/abi/abi-tag14.C b/gcc/testsuite/g++.dg/abi/abi-tag14.C new file mode 100644 index 00000000000..a66e6552cba --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/abi-tag14.C @@ -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 T g() { } +template <> A g() { } + +// { dg-final { scan-assembler "_Z1vIN7__cxx111AEE" { target c++14 } } } +#if __cplusplus >= 201402L +template T v = T(); +void *p = &v; +#endif diff --git a/gcc/testsuite/g++.dg/abi/abi-tag4.C b/gcc/testsuite/g++.dg/abi/abi-tag4.C index 3f8d7bfbc3d..6bf4fa1c538 100644 --- a/gcc/testsuite/g++.dg/abi/abi-tag4.C +++ b/gcc/testsuite/g++.dg/abi/abi-tag4.C @@ -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" } }; diff --git a/gcc/testsuite/g++.dg/abi/abi-tag8.C b/gcc/testsuite/g++.dg/abi/abi-tag8.C index 0a6eb5802af..7ead1cb86b4 100644 --- a/gcc/testsuite/g++.dg/abi/abi-tag8.C +++ b/gcc/testsuite/g++.dg/abi/abi-tag8.C @@ -4,6 +4,6 @@ template struct __attribute ((__abi_tag__("cxx11"))) list // { dg-message "list" } { }; -struct X { // { dg-warning "abi tag" } +struct X { // { dg-warning "ABI tag" } list l; // { dg-message "X::l" } }; diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 4fe0c645687..6836423e7d1 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,8 @@ +2015-03-19 Jason Merrill + + * 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 PR c++/65046 diff --git a/libstdc++-v3/config/locale/gnu/messages_members.cc b/libstdc++-v3/config/locale/gnu/messages_members.cc index c90499e26a9..2e6122d2ea5 100644 --- a/libstdc++-v3/config/locale/gnu/messages_members.cc +++ b/libstdc++-v3/config/locale/gnu/messages_members.cc @@ -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 _M_infos; }; - _GLIBCXX_DEFAULT_ABI_TAG Catalogs& get_catalogs() { diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config index 46ffa1f5d0a..eebe34c604c 100644 --- a/libstdc++-v3/include/bits/c++config +++ b/libstdc++-v3/include/bits/c++config @@ -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 { diff --git a/libstdc++-v3/src/c++11/cxx11-shim_facets.cc b/libstdc++-v3/src/c++11/cxx11-shim_facets.cc index a32b9f0b65f..4e30088bac3 100644 --- a/libstdc++-v3/src/c++11/cxx11-shim_facets.cc +++ b/libstdc++-v3/src/c++11/cxx11-shim_facets.cc @@ -227,8 +227,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace // unnamed { template - 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 - 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 - 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 - 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 - 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 - 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 - 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;