This patch makes some significant changes to attribute abi_tag.
First, it allows explicit naming of tags on inline namespaces, which previously always had a tag with the same name as the namespace itself; this is still the default if no tag is specified.
It also introduces automatic tagging of functions and variables with tagged types where the tags are not already reflected in the mangled name. I feel somewhat uneasy about this change, but I think it's the right answer. -Wabi-tag will also warn about this so that people are aware of it and can tag explicitly if they want to.
A smaller change is introducing a macro to check for inline namespaces, which were previously completely indistinguishable without checking for the strong using in the enclosing namespace.
I'm also reverting some libstdc++ changes to add ABI tags to things in anonymous namespaces, which have no external ABI so we shouldn't care about their mangled names.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 525578ca03ac5d451ca4bd604357e1c90ac6e671 Author: Jason Merrill <ja...@redhat.com> Date: Tue Mar 10 15:34:49 2015 -0400 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. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 8612163..0518320 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<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); - - 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); - } - } + mark_or_check_tags (*tp, tp, p, false); + + return NULL_TREE; +} + +/* 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 (transitively - complete) template arguments. */ +/* 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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 65219f1..7111449 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 fbf4bf2..b0f72d1 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)); +} + /* <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)) diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index ba16bef..c845d52 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 a18f38c..98d741f 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 c8e6f0c..ef53aff 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 91b94f7..c6fdb24 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 f2ab517..133cca9 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 942929c..d57ed87 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 0000000..a66e655 --- /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 <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 diff --git a/gcc/testsuite/g++.dg/abi/abi-tag4.C b/gcc/testsuite/g++.dg/abi/abi-tag4.C index 3f8d7bf..6bf4fa1 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 0a6eb58..7ead1cb 100644 --- a/gcc/testsuite/g++.dg/abi/abi-tag8.C +++ b/gcc/testsuite/g++.dg/abi/abi-tag8.C @@ -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" } }; diff --git a/libstdc++-v3/config/locale/gnu/messages_members.cc b/libstdc++-v3/config/locale/gnu/messages_members.cc index c90499e..2e6122d 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<Catalog_info*> _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 46ffa1f..eebe34c 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 a32b9f0..4e30088 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<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;