public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCH for c++/65046 (ABI tags and functions/variables)
@ 2015-03-19 19:17 Jason Merrill
  2015-04-04 11:38 ` Markus Trippelsdorf
  0 siblings, 1 reply; 6+ messages in thread
From: Jason Merrill @ 2015-03-19 19:17 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 1004 bytes --]

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.

[-- Attachment #2: 65046.patch --]
[-- Type: text/x-patch, Size: 30188 bytes --]

commit 525578ca03ac5d451ca4bd604357e1c90ac6e671
Author: Jason Merrill <jason@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;

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: C++ PATCH for c++/65046 (ABI tags and functions/variables)
  2015-03-19 19:17 C++ PATCH for c++/65046 (ABI tags and functions/variables) Jason Merrill
@ 2015-04-04 11:38 ` Markus Trippelsdorf
  2015-04-06 12:59   ` Jason Merrill
  0 siblings, 1 reply; 6+ messages in thread
From: Markus Trippelsdorf @ 2015-04-04 11:38 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List

On 2015.03.19 at 15:17 -0400, Jason Merrill wrote:
> 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.

This breaks compatibility with other compilers. Consider the case when
a user compiles a library, that contains e.g. some member function with
a std::string return type, with clang using gcc-5's libstdc++. It will
be mangled without abi-tags, because clang doesn't support them. 
Now when the user switches back to gcc-5 and uses the libraries headers
in a new project he will get undefined symbol errors when linking with
the library, because gcc-5 adds an abi-tag to the member function
declaration.

Another issue is that the -Wabi-tag warning isn't enabled by -Wall or
even by -Wextra.

-- 
Markus

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: C++ PATCH for c++/65046 (ABI tags and functions/variables)
  2015-04-04 11:38 ` Markus Trippelsdorf
@ 2015-04-06 12:59   ` Jason Merrill
  2015-04-06 13:23     ` Markus Trippelsdorf
  0 siblings, 1 reply; 6+ messages in thread
From: Jason Merrill @ 2015-04-06 12:59 UTC (permalink / raw)
  To: Markus Trippelsdorf; +Cc: gcc-patches List

On 04/04/2015 07:38 AM, Markus Trippelsdorf wrote:
> This breaks compatibility with other compilers. Consider the case when
> a user compiles a library, that contains e.g. some member function with
> a std::string return type, with clang using gcc-5's libstdc++. It will
> be mangled without abi-tags, because clang doesn't support them.
> Now when the user switches back to gcc-5 and uses the libraries headers
> in a new project he will get undefined symbol errors when linking with
> the library, because gcc-5 adds an abi-tag to the member function
> declaration.

I don't know what clang will do with GCC 5's libstdc++, but if it 
doesn't support ABI tags then in the best case it will use the old ABI, 
and so undefined symbol errors are exactly what we want, rather than 
runtime corruption.

> Another issue is that the -Wabi-tag warning isn't enabled by -Wall or
> even by -Wextra.

That's because I think the warning is mostly interesting for library 
vendors; most users shouldn't need to worry about it.

Jason

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: C++ PATCH for c++/65046 (ABI tags and functions/variables)
  2015-04-06 12:59   ` Jason Merrill
@ 2015-04-06 13:23     ` Markus Trippelsdorf
  2015-04-06 20:45       ` Jason Merrill
  0 siblings, 1 reply; 6+ messages in thread
From: Markus Trippelsdorf @ 2015-04-06 13:23 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List

On 2015.04.06 at 08:41 -0400, Jason Merrill wrote:
> On 04/04/2015 07:38 AM, Markus Trippelsdorf wrote:
> > This breaks compatibility with other compilers. Consider the case when
> > a user compiles a library, that contains e.g. some member function with
> > a std::string return type, with clang using gcc-5's libstdc++. It will
> > be mangled without abi-tags, because clang doesn't support them.
> > Now when the user switches back to gcc-5 and uses the libraries headers
> > in a new project he will get undefined symbol errors when linking with
> > the library, because gcc-5 adds an abi-tag to the member function
> > declaration.
> 
> I don't know what clang will do with GCC 5's libstdc++, but if it 
> doesn't support ABI tags then in the best case it will use the old ABI, 
> and so undefined symbol errors are exactly what we want, rather than 
> runtime corruption.

The issue is that clang uses the new libstdc++ ABI just fine. And before
this commit one could switch compilers without any problems...

-- 
Markus

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: C++ PATCH for c++/65046 (ABI tags and functions/variables)
  2015-04-06 13:23     ` Markus Trippelsdorf
@ 2015-04-06 20:45       ` Jason Merrill
  2015-04-06 21:31         ` Markus Trippelsdorf
  0 siblings, 1 reply; 6+ messages in thread
From: Jason Merrill @ 2015-04-06 20:45 UTC (permalink / raw)
  To: Markus Trippelsdorf; +Cc: gcc-patches List, Jonathan Wakely

On 04/06/2015 09:23 AM, Markus Trippelsdorf wrote:
> The issue is that clang uses the new libstdc++ ABI just fine. And before
> this commit one could switch compilers without any problems...

Hmm, I suppose that when we switched to using inline namespaces for much 
of the new ABI, switching compilers became more feasible; now tags are 
only used for functions and variables, so you're less likely to run into 
a problem, but it could still cause trouble if you use one of the tagged 
functions in libstdc++ and get the one returning an old-ABI string.  So 
I would be nervous about using clang with a dual-ABI libstdc++.  Does 
clang use the new ABI by default with GCC 5 libstdc++?  If it uses the 
old ABI then using the un-tagged function names is fine, but we don't 
want it to link with code that uses the new ABI.

Jason

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: C++ PATCH for c++/65046 (ABI tags and functions/variables)
  2015-04-06 20:45       ` Jason Merrill
@ 2015-04-06 21:31         ` Markus Trippelsdorf
  0 siblings, 0 replies; 6+ messages in thread
From: Markus Trippelsdorf @ 2015-04-06 21:31 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List, Jonathan Wakely

On 2015.04.06 at 16:45 -0400, Jason Merrill wrote:
> On 04/06/2015 09:23 AM, Markus Trippelsdorf wrote:
> > The issue is that clang uses the new libstdc++ ABI just fine. And before
> > this commit one could switch compilers without any problems...
> 
> Hmm, I suppose that when we switched to using inline namespaces for much 
> of the new ABI, switching compilers became more feasible; now tags are 
> only used for functions and variables, so you're less likely to run into 
> a problem, but it could still cause trouble if you use one of the tagged 
> functions in libstdc++ and get the one returning an old-ABI string.  So 
> I would be nervous about using clang with a dual-ABI libstdc++.  Does 
> clang use the new ABI by default with GCC 5 libstdc++? 

Yes, (unless you explicitly use -D_GLIBCXX_USE_CXX11_ABI=0).

I think most distros will use -D_GLIBCXX_USE_CXX11_ABI=0 for gcc-5, but
on my Gentoo testbox I've already switched to the new ABI. And before your
commit I could compile libraries with gcc and then use them with clang
(and vice versa) without any issues. Now every library function with a
std::string return type may cause linker errors.

-- 
Markus

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-04-06 21:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-19 19:17 C++ PATCH for c++/65046 (ABI tags and functions/variables) Jason Merrill
2015-04-04 11:38 ` Markus Trippelsdorf
2015-04-06 12:59   ` Jason Merrill
2015-04-06 13:23     ` Markus Trippelsdorf
2015-04-06 20:45       ` Jason Merrill
2015-04-06 21:31         ` Markus Trippelsdorf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).