re PR c++/65046 (-Wabi-tag doesn't warn about variables or function return types)
authorJason Merrill <jason@redhat.com>
Thu, 19 Mar 2015 19:31:48 +0000 (15:31 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 19 Mar 2015 19:31:48 +0000 (15:31 -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.

From-SVN: r221521

17 files changed:
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/mangle.c
gcc/cp/name-lookup.c
gcc/cp/parser.c
gcc/cp/tree.c
gcc/doc/extend.texi
gcc/doc/invoke.texi
gcc/testsuite/g++.dg/abi/abi-tag1.C
gcc/testsuite/g++.dg/abi/abi-tag14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/abi/abi-tag4.C
gcc/testsuite/g++.dg/abi/abi-tag8.C
libstdc++-v3/ChangeLog
libstdc++-v3/config/locale/gnu/messages_members.cc
libstdc++-v3/include/bits/c++config
libstdc++-v3/src/c++11/cxx11-shim_facets.cc

index f8ebb2dcfa9f18601a057c0f7efd0aeb1539bbc0..f90e447cc988f26825fcbcaaf384f839c2a11901 100644 (file)
@@ -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"
index 8612163711cf3e0708c702eb4f4c7a1e851c38b6..0518320d6b9953517fc72fe7f075fb3747dbf1ee 100644 (file)
@@ -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 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<bool*>(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
index 65219f159e326a77d20bceb9b85750a30c639b12..7111449da4b55d45ecb5fece8858d77d3c0983db 100644 (file)
@@ -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);
index fbf4bf27c077368c050f336cd8ccc538d694b8af..b0f72d1ff14e37c9c210e331cc2bb5a0e0e3d6b6 100644 (file)
@@ -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))
index ba16befa74d9d5499a4ab724d91d757ed34bf948..c845d521a53ebc319ee34896f070f4d5d928b58b 100644 (file)
@@ -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
        {
index a18f38ce0af87ffe03a67e35770f91172657fb49..98d741f440a720182ae9887936b8906f7da2da11 100644 (file)
@@ -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,
index c8e6f0c796f68fb2a8288397920bf07d333c0a4b..ef53aff87f74cff4427b9aa5a8a8829166f90e43 100644 (file)
@@ -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;
        }
index 91b94f7b610b79ee71451ae20b5e2ed4c1ecd93f..c6fdb2453c85b81bafae5d12e4e77934db8ebb29 100644 (file)
@@ -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
 
index f2ab51744dc114bfc58f84b09b340bb6750d93db..133cca9042ec630a385852508e376f02ee8ee6a6 100644 (file)
@@ -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
index 942929cdd35f456acdd22519af09e0726da9ebe1..d57ed87d80378e88534b9b0d236c184ee9c0627e 100644 (file)
@@ -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 (file)
index 0000000..a66e655
--- /dev/null
@@ -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
index 3f8d7bfbc3d441b333c3936dea97358fb3ad2ec4..6bf4fa1c538575edca149a3ef1e471c0697801a6 100644 (file)
@@ -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" }
 };
index 0a6eb5802afeea9f2dc680fc960e93483e3d2897..7ead1cb86b44f2c68a73578ba9b9ce230524af57 100644 (file)
@@ -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" }
 };
index 4fe0c6456872fc643af77a1c2709813d8bda6ef3..6836423e7d1be274249fc06d955dcc6c51733cbe 100644 (file)
@@ -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
index c90499e26a910d7c2884c5a66032af52f98182d4..2e6122d2ea520fca9f44659b2b34d9c6f1fa1772 100644 (file)
@@ -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()
   {
index 46ffa1f5d0a36c085879785e62e180bc9239b5b3..eebe34c604c636edd99beaf3ddae0757f8d9bb8c 100644 (file)
@@ -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 {
index a32b9f0b65f5c0cb94ccc5156dafb32e073b0b6a..4e30088bac3732520c35744018ed8bd5940277b0 100644 (file)
@@ -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;