I remember thinking that I'd need to deal with mangling for
ref-qualifiers, but somehow it slipped my mind. This patch implements
it. Having to mess with re-adding the ref-qualifier after
TYPE_MAIN_VARIANT makes me more determined to deal with giving
ref-qualified types their own TYPE_MAIN_VARIANT, but this patch fixes
the issue relatively non-invasively; the better fix for 4.9 can come later.
Tested x86_64-pc-linux-gnu, applying to trunk and 4.8.
commit 9231fd034c771ca295590e69381001e759f9e3ae
Author: Jason Merrill <ja...@redhat.com>
Date: Tue Apr 2 20:50:21 2013 -0400
PR c++/56821
* mangle.c (write_function_type): Mangle ref-qualifier.
(write_nested_name): Likewise.
(canonicalize_for_substitution): Preserve ref-qualifier.
(write_type): Likewise.
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index a48d476..10c2e2b 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -350,6 +350,7 @@ canonicalize_for_substitution (tree node)
&& TYPE_CANONICAL (node) != node
&& TYPE_MAIN_VARIANT (node) != node)
{
+ tree orig = node;
/* Here we want to strip the topmost typedef only.
We need to do that so is_std_substitution can do proper
name matching. */
@@ -361,6 +362,9 @@ canonicalize_for_substitution (tree node)
else
node = cp_build_qualified_type (TYPE_MAIN_VARIANT (node),
cp_type_quals (node));
+ if (TREE_CODE (node) == FUNCTION_TYPE
+ || TREE_CODE (node) == METHOD_TYPE)
+ node = build_ref_qualified_type (node, type_memfn_rqual (orig));
}
return node;
}
@@ -904,9 +908,11 @@ write_unscoped_template_name (const tree decl)
/* Write the nested name, including CV-qualifiers, of DECL.
- <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
- ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+ <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+ ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+ <ref-qualifier> ::= R # & ref-qualifier
+ ::= O # && ref-qualifier
<CV-qualifiers> ::= [r] [V] [K] */
static void
@@ -926,6 +932,13 @@ write_nested_name (const tree decl)
write_char ('V');
if (DECL_CONST_MEMFUNC_P (decl))
write_char ('K');
+ if (FUNCTION_REF_QUALIFIED (TREE_TYPE (decl)))
+ {
+ if (FUNCTION_RVALUE_QUALIFIED (TREE_TYPE (decl)))
+ write_char ('O');
+ else
+ write_char ('R');
+ }
}
/* Is this a template instance? */
@@ -1880,7 +1893,13 @@ write_type (tree type)
mangle the unqualified type. The recursive call is needed here
since both the qualified and unqualified types are substitution
candidates. */
- write_type (TYPE_MAIN_VARIANT (type));
+ {
+ tree t = TYPE_MAIN_VARIANT (type);
+ if (TREE_CODE (t) == FUNCTION_TYPE
+ || TREE_CODE (t) == METHOD_TYPE)
+ t = build_ref_qualified_type (t, type_memfn_rqual (type));
+ write_type (t);
+ }
else if (TREE_CODE (type) == ARRAY_TYPE)
/* It is important not to use the TYPE_MAIN_VARIANT of TYPE here
so that the cv-qualification of the element type is available
@@ -1892,6 +1911,9 @@ write_type (tree type)
/* See through any typedefs. */
type = TYPE_MAIN_VARIANT (type);
+ if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE)
+ type = build_ref_qualified_type (type, type_memfn_rqual (type_orig));
/* According to the C++ ABI, some library classes are passed the
same as the scalar type of their single member and use the same
@@ -2327,7 +2349,7 @@ write_builtin_type (tree type)
METHOD_TYPE. The return type is mangled before the parameter
types.
- <function-type> ::= F [Y] <bare-function-type> E */
+ <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E */
static void
write_function_type (const tree type)
@@ -2360,6 +2382,13 @@ write_function_type (const tree type)
See [dcl.link]. */
write_bare_function_type (type, /*include_return_type_p=*/1,
/*decl=*/NULL);
+ if (FUNCTION_REF_QUALIFIED (type))
+ {
+ if (FUNCTION_RVALUE_QUALIFIED (type))
+ write_char ('O');
+ else
+ write_char ('R');
+ }
write_char ('E');
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-qual-mangle1.C b/gcc/testsuite/g++.dg/cpp0x/ref-qual-mangle1.C
new file mode 100644
index 0000000..c6ef079
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/ref-qual-mangle1.C
@@ -0,0 +1,37 @@
+// PR c++/56821
+// { dg-require-effective-target c++11 }
+
+struct A {
+ // { dg-final { scan-assembler "_ZNR1A1fEv" } }
+ void f() & {}
+ // { dg-final { scan-assembler "_ZNO1A1gEv" } }
+ void g() && {}
+ // { dg-final { scan-assembler "_ZNKR1A1hEv" } }
+ void h() const & {}
+};
+
+// { dg-final { scan-assembler "_Z1jM1AFvvRE" } }
+void j(void (A::*)() &) { }
+// { dg-final { scan-assembler "_Z1kM1AFvvOE" } }
+void k(void (A::*)() &&) { }
+// { dg-final { scan-assembler "_Z1lM1AKFvvRE" } }
+void l(void (A::*)() const &) { }
+
+// { dg-final { scan-assembler "_Z1mIFvvOEEvM1AT_" } }
+// { dg-final { scan-assembler "_Z1mIFvvREEvM1AT_" } }
+// { dg-final { scan-assembler "_Z1mIKFvvREEvM1AT_" } }
+template <typename T>
+void m(T A::*) {}
+
+// { dg-final { scan-assembler "_Z1nIM1AFvvOEEvT_" } }
+// { dg-final { scan-assembler "_Z1nIM1AFvvREEvT_" } }
+// { dg-final { scan-assembler "_Z1nIM1AKFvvREEvT_" } }
+template <typename T>
+void n(T) {}
+
+int main()
+{
+ j(&A::f); k(&A::g); l(&A::h);
+ m(&A::f); m(&A::g); m(&A::h);
+ n(&A::f); n(&A::g); n(&A::h);
+}