Patchwork C++ PATCH for c++/56821 (ref-qualifier mangling)

login
register
mail settings
Submitter Jason Merrill
Date April 3, 2013, 3:13 a.m.
Message ID <515B9E6C.2090600@redhat.com>
Download mbox | patch
Permalink /patch/233212/
State New
Headers show

Comments

Jason Merrill - April 3, 2013, 3:13 a.m.
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.

Patch

commit 9231fd034c771ca295590e69381001e759f9e3ae
Author: Jason Merrill <jason@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);
+}