This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
RFA (varpool): PATCH to add forward-compatibility aliases for C++ ABI bugs
- From: Jason Merrill <jason at redhat dot com>
- To: "Hubicha, Jan" <jh at suse dot cz>
- Cc: gcc-patches List <gcc-patches at gcc dot gnu dot org>, Jakub Jelinek <jakub at redhat dot com>
- Date: Thu, 25 Feb 2010 16:58:37 -0500
- Subject: 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" }