This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA (varpool): PATCH to add forward-compatibility aliases for C++ ABI bugs


The attached patch addresses some binary compatibility issues with bugs in our current implementation of the C++ ABI by emitting aliases with ABI-compliant mangled names in addition to the names generated normally.

I need review of the cgraph.h and varpool.c hunks. They basically add the same capability to the varpool code that Jakub added to cgraph with the cgraph_same_body_alias code. This code is much simpler, but it seems to me like it's enough given the relative simplicity of varpool.

Tested x86_64-pc-linux-gnu. OK for 4.5?
commit 101ce01b5e9f270072e1e93a760f0daa76e4b8fb
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Feb 23 18:03:21 2010 -0500

    	PR c++/12909
    	* mangle.c: Include cgraph.h.
    	(mangle_decl): If the mangled name will change in a later
    	ABI version, make the later mangled name an alias.
    	* Make-lang.in (mangle.o): Depend on cgraph.h.

diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index f6cb70f..1484063 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -308,7 +308,7 @@ cp/optimize.o: cp/optimize.c $(CXX_TREE_H) $(TM_H) rtl.h $(INTEGRATE_H) \
   insn-config.h input.h $(PARAMS_H) debug.h $(TREE_INLINE_H) $(GIMPLE_H) \
   $(TARGET_H) tree-iterator.h $(CGRAPH_H)
 cp/mangle.o: cp/mangle.c $(CXX_TREE_H) $(TM_H) toplev.h $(REAL_H) \
-  gt-cp-mangle.h $(TARGET_H) $(TM_P_H)
+  gt-cp-mangle.h $(TARGET_H) $(TM_P_H) $(CGRAPH_H)
 cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_H) gt-cp-parser.h \
   output.h $(TARGET_H) $(PLUGIN_H) intl.h
 cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) toplev.h $(C_COMMON_H) \
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index e6d7934..56c275b 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "varray.h"
 #include "flags.h"
 #include "target.h"
+#include "cgraph.h"
 
 /* Debugging support.  */
 
@@ -3031,6 +3032,27 @@ mangle_decl (const tree decl)
   tree id = mangle_decl_string (decl);
   id = targetm.mangle_decl_assembler_name (decl, id);
   SET_DECL_ASSEMBLER_NAME (decl, id);
+
+#ifdef ASM_OUTPUT_DEF
+  if (G.need_abi_warning && TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      /* If the mangling will change in the future, emit an alias with the
+	 future mangled name for forward-compatibility.  */
+      int save_ver = flag_abi_version;
+      tree id2, alias;
+      flag_abi_version = 0;
+      id2 = mangle_decl_string (decl);
+      id2 = targetm.mangle_decl_assembler_name (decl, id2);
+      flag_abi_version = save_ver;
+
+      alias = make_alias_for (decl, id2);
+      TREE_PUBLIC (alias) = TREE_PUBLIC (decl);
+      DECL_VISIBILITY (alias) = DECL_VISIBILITY (decl);
+      if (vague_linkage_fn_p (decl))
+	DECL_WEAK (alias) = 1;
+      cgraph_same_body_alias (alias, decl);
+    }
+#endif
 }
 
 /* Generate the mangled representation of TYPE.  */

commit eb0cc4fa8b6d747f96bd1f0aa05828d83499ba13
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Feb 25 10:21:33 2010 -0500

    	PR c++/12909
    	* method.c (make_alias_for): Handle VAR_DECL, too.
    	* decl2.c (vague_linkage_p): Rename from vague_linkage_fn_p.
    	* tree.c (no_linkage_check): Adjust.
    	* decl.c (maybe_commonize_var): Adjust.
    	* cp-tree.h: Adjust.
    	* cp-tree.h: Adjust.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index aff3f91..0cc2b1a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4735,7 +4735,7 @@ extern tree build_memfn_type			(tree, tree, cp_cv_quals);
 extern tree change_return_type			(tree, tree);
 extern void maybe_retrofit_in_chrg		(tree);
 extern void maybe_make_one_only			(tree);
-extern bool vague_linkage_fn_p			(tree);
+extern bool vague_linkage_p			(tree);
 extern void grokclassfn				(tree, tree,
 						 enum overload_flags);
 extern tree grok_array_decl			(tree, tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 3eec0c7..67377b0 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4642,7 +4642,7 @@ maybe_commonize_var (tree decl)
       /* Don't mess with __FUNCTION__.  */
       && ! DECL_ARTIFICIAL (decl)
       && DECL_FUNCTION_SCOPE_P (decl)
-      && vague_linkage_fn_p (DECL_CONTEXT (decl)))
+      && vague_linkage_p (DECL_CONTEXT (decl)))
     {
       if (flag_weak)
 	{
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index c5b6e87..81d7ee3 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1642,20 +1642,21 @@ maybe_make_one_only (tree decl)
     }
 }
 
-/* Returns true iff DECL, a FUNCTION_DECL, has vague linkage.  This
-   predicate will give the right answer during parsing of the function,
-   which other tests may not.  */
+/* Returns true iff DECL, a FUNCTION_DECL or VAR_DECL, has vague linkage.
+   This predicate will give the right answer during parsing of the
+   function, which other tests may not.  */
 
 bool
-vague_linkage_fn_p (tree fn)
+vague_linkage_p (tree decl)
 {
   /* Unfortunately, import_export_decl has not always been called
      before the function is processed, so we cannot simply check
      DECL_COMDAT.  */
-  return (DECL_COMDAT (fn)
-	  || ((DECL_DECLARED_INLINE_P (fn)
-	       || DECL_TEMPLATE_INSTANTIATION (fn))
-	      && TREE_PUBLIC (fn)));
+  return (DECL_COMDAT (decl)
+	  || (((TREE_CODE (decl) == FUNCTION_DECL
+		&& DECL_DECLARED_INLINE_P (decl))
+	       || DECL_TEMPLATE_INSTANTIATION (decl))
+	      && TREE_PUBLIC (decl)));
 }
 
 /* Determine whether or not we want to specifically import or export CTYPE,
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 56c275b..9c445fa 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -3048,7 +3048,7 @@ mangle_decl (const tree decl)
       alias = make_alias_for (decl, id2);
       TREE_PUBLIC (alias) = TREE_PUBLIC (decl);
       DECL_VISIBILITY (alias) = DECL_VISIBILITY (decl);
-      if (vague_linkage_fn_p (decl))
+      if (vague_linkage_p (decl))
 	DECL_WEAK (alias) = 1;
       cgraph_same_body_alias (alias, decl);
     }
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index ccc977d..3c7df1f 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -207,33 +207,36 @@ finish_thunk (tree thunk)
 
 static GTY (()) int thunk_labelno;
 
-/* Create a static alias to function.  */
+/* Create a static alias to target.  */
 
 tree
-make_alias_for (tree function, tree newid)
+make_alias_for (tree target, tree newid)
 {
-  tree alias = build_decl (DECL_SOURCE_LOCATION (function),
-			   FUNCTION_DECL, newid, TREE_TYPE (function));
-  DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
+  tree alias = build_decl (DECL_SOURCE_LOCATION (target),
+			   TREE_CODE (target), newid, TREE_TYPE (target));
+  DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (target);
   cxx_dup_lang_specific_decl (alias);
   DECL_CONTEXT (alias) = NULL;
-  TREE_READONLY (alias) = TREE_READONLY (function);
-  TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function);
+  TREE_READONLY (alias) = TREE_READONLY (target);
+  TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (target);
   TREE_PUBLIC (alias) = 0;
   DECL_INTERFACE_KNOWN (alias) = 1;
   DECL_NOT_REALLY_EXTERN (alias) = 1;
   DECL_THIS_STATIC (alias) = 1;
-  DECL_SAVED_FUNCTION_DATA (alias) = NULL;
-  DECL_DESTRUCTOR_P (alias) = 0;
-  DECL_CONSTRUCTOR_P (alias) = 0;
   DECL_EXTERNAL (alias) = 0;
   DECL_ARTIFICIAL (alias) = 1;
-  DECL_PENDING_INLINE_P (alias) = 0;
-  DECL_DECLARED_INLINE_P (alias) = 0;
   DECL_USE_TEMPLATE (alias) = 0;
   DECL_TEMPLATE_INSTANTIATED (alias) = 0;
   DECL_TEMPLATE_INFO (alias) = NULL;
-  DECL_INITIAL (alias) = error_mark_node;
+  if (TREE_CODE (alias) == FUNCTION_DECL)
+    {
+      DECL_SAVED_FUNCTION_DATA (alias) = NULL;
+      DECL_DESTRUCTOR_P (alias) = 0;
+      DECL_CONSTRUCTOR_P (alias) = 0;
+      DECL_PENDING_INLINE_P (alias) = 0;
+      DECL_DECLARED_INLINE_P (alias) = 0;
+      DECL_INITIAL (alias) = error_mark_node;
+    }
   TREE_ADDRESSABLE (alias) = 1;
   TREE_USED (alias) = 1;
   SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 31b54f6..9867d2e 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1607,7 +1607,7 @@ no_linkage_check (tree t, bool relaxed_p)
 	    return no_linkage_check (TYPE_CONTEXT (t), relaxed_p);
 	  else if (TREE_CODE (r) == FUNCTION_DECL)
 	    {
-	      if (!relaxed_p || !vague_linkage_fn_p (r))
+	      if (!relaxed_p || !vague_linkage_p (r))
 		return t;
 	      else
 		r = CP_DECL_CONTEXT (r);

commit 0056338b1e3d1f97113de39fe0e1bd170c909f44
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Feb 25 11:23:07 2010 -0500

    	PR c++/12909
    	* cgraph.h (varpool_node): Add extra_name field.
    	* varpool.c (varpool_extra_name_alias): New.
    	(varpool_assemble_decl): Emit extra name aliases.
    cp/
    	* mangle.c (mangle_decl): Handle VAR_DECL, too.

diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 802b280..f8d52eb 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -361,6 +361,9 @@ struct GTY((chain_next ("%h.next"))) varpool_node {
   struct varpool_node *next;
   /* Pointer to the next function in varpool_nodes_queue.  */
   struct varpool_node *next_needed;
+  /* For normal nodes a pointer to the first extra name alias.  For alias
+     nodes a pointer to the normal node.  */
+  struct varpool_node *extra_name;
   /* Ordering of all cgraph nodes.  */
   int order;
 
@@ -379,7 +382,8 @@ struct GTY((chain_next ("%h.next"))) varpool_node {
   unsigned output : 1;
   /* Set when function is visible by other units.  */
   unsigned externally_visible : 1;
-  /* Set for aliases once they got through assemble_alias.  */
+  /* Set for aliases once they got through assemble_alias.  Also set for
+     extra name aliases in varpool_extra_name_alias.  */
   unsigned alias : 1;
 };
 
@@ -574,6 +578,7 @@ bool varpool_assemble_decl (struct varpool_node *node);
 bool varpool_analyze_pending_decls (void);
 void varpool_remove_unreferenced_decls (void);
 void varpool_empty_needed_queue (void);
+bool varpool_extra_name_alias (tree, tree);
 const char * varpool_node_name (struct varpool_node *node);
 
 /* Walk all reachable static variables.  */
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 9c445fa..a0a43c9 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -3034,7 +3034,7 @@ mangle_decl (const tree decl)
   SET_DECL_ASSEMBLER_NAME (decl, id);
 
 #ifdef ASM_OUTPUT_DEF
-  if (G.need_abi_warning && TREE_CODE (decl) == FUNCTION_DECL)
+  if (G.need_abi_warning)
     {
       /* If the mangling will change in the future, emit an alias with the
 	 future mangled name for forward-compatibility.  */
@@ -3050,7 +3050,10 @@ mangle_decl (const tree decl)
       DECL_VISIBILITY (alias) = DECL_VISIBILITY (decl);
       if (vague_linkage_p (decl))
 	DECL_WEAK (alias) = 1;
-      cgraph_same_body_alias (alias, decl);
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	cgraph_same_body_alias (alias, decl);
+      else
+	varpool_extra_name_alias (alias, decl);
     }
 #endif
 }
diff --git a/gcc/varpool.c b/gcc/varpool.c
index 157755b..63febfa 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -383,9 +383,22 @@ varpool_assemble_decl (struct varpool_node *node)
       assemble_variable (decl, 0, 1, 0);
       if (TREE_ASM_WRITTEN (decl))
 	{
+	  struct varpool_node *alias;
+
 	  node->next_needed = varpool_assembled_nodes_queue;
 	  varpool_assembled_nodes_queue = node;
 	  node->finalized = 1;
+
+	  /* Also emit any extra name aliases.  */
+	  for (alias = node->extra_name; alias; alias = alias->next)
+	    {
+	      /* Update linkage fields in case they've changed.  */
+	      DECL_WEAK (alias->decl) = DECL_WEAK (decl);
+	      TREE_PUBLIC (alias->decl) = TREE_PUBLIC (decl);
+	      DECL_VISIBILITY (alias->decl) = DECL_VISIBILITY (decl);
+	      assemble_alias (alias->decl, DECL_ASSEMBLER_NAME (decl));
+	    }
+
 	  return true;
 	}
     }
@@ -507,4 +520,39 @@ add_new_static_var (tree type)
   return new_node->decl;
 }
 
+/* Attempt to mark ALIAS as an alias to DECL.  Return TRUE if successful.
+   Extra name aliases are output whenever DECL is output.  */
+
+bool
+varpool_extra_name_alias (tree alias, tree decl)
+{
+  struct varpool_node key, *alias_node, *decl_node, **slot;
+
+#ifndef ASM_OUTPUT_DEF
+  /* If aliases aren't supported by the assembler, fail.  */
+  return false;
+#endif
+
+  gcc_assert (TREE_CODE (decl) == VAR_DECL);
+  gcc_assert (TREE_CODE (alias) == VAR_DECL);
+
+  key.decl = alias;
+
+  slot = (struct varpool_node **) htab_find_slot (varpool_hash, &key, INSERT);
+
+  /* If the varpool_node has been already created, fail.  */
+  if (*slot)
+    return false;
+
+  decl_node = varpool_node (decl);
+  alias_node = GGC_CNEW (struct varpool_node);
+  alias_node->decl = alias;
+  alias_node->alias = 1;
+  alias_node->extra_name = decl_node;
+  alias_node->next = decl_node->extra_name;
+  decl_node->extra_name = alias_node;
+  *slot = alias_node;
+  return true;
+}
+
 #include "gt-varpool.h"

commit feefe649311d802cdcf86e39c2be42b2acb6dbea
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Feb 24 00:40:03 2010 -0500

    	PR c++/12909
    	* g++.dg/abi/mangle40.C: New.

diff --git a/gcc/testsuite/g++.dg/abi/mangle40.C b/gcc/testsuite/g++.dg/abi/mangle40.C
new file mode 100644
index 0000000..2fdd239
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle40.C
@@ -0,0 +1,26 @@
+// PR c++/12909
+// { dg-do compile { target i?86-*-* x86_64-*-* } }
+// { dg-options "-mavx -Wabi" }
+// { dg-final { scan-assembler "weak\[^\n\]*_Z1fIDv4_fEvT_" } }
+// { dg-final { scan-assembler "weak\[^\n\]*_Z1fIU8__vectorfEvT_" } }
+// { dg-final { scan-assembler "weak\[^\n\]*_ZN1AIDv4_fE1tE" } }
+// { dg-final { scan-assembler "weak\[^\n\]*_ZN1AIU8__vectorfE1tE" } }
+
+#include <x86intrin.h>
+
+template <class T>
+struct A
+{
+  static T t;
+};
+
+template <class T>
+T A<T>::t;
+
+template <class T>
+void f (T t) { }		// { dg-warning "mangled name" }
+
+int main()
+{
+  f (A<__m128>::t);
+} // { dg-warning "mangled name" }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]