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]

C++ PATCH to implement C++11 ref-qualifiers


This patch implements the last major missing bullet point in the C++11 features list, support for ref-qualifiers to allow member functions to apply to either lvalues or rvalues only:

  struct A
  {
    void f() &;  // requires an lvalue
    void g() &&; // requires an rvalue
  };

Bronek did most of the work months back, but it took a long time to get his copyright assignment processed, and since that was taken care of he hasn't had time to finish the work, so I've done the last bits. Thanks a lot!

I was surprised how contained the changes to implement the overload resolution were; I just needed a few lines in add_function_candidate. But relying on build_fold_indirect_ref to undo the effect of build_this fragile, so on the trunk I'm going to defer build_this until we're actually doing the conversions. The third commit in the patch does that.

The second commit in the patch is some cleanups I noticed while working on this to make things more tidy.

Applying everything to trunk, first commit to 4.8.
commit a7f0db6f5ca96c5eb8d9b1ceb50b3d3a0a5e05e9
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Apr 1 14:05:24 2013 -0400

    	Implement N2439 (ref-qualifiers for 'this')
    	* cp-tree.h (FUNCTION_REF_QUALIFIED): New.
    	(FUNCTION_RVALUE_QUALIFIED): New.
    	(FUNCTION_OR_METHOD_TYPE_CHECK): New.
    	(cpp0x_warn_str): Add CPP0X_REF_QUALIFIER.
    	(cp_ref_qualifier): New enum.
    	(cp_declarator): Add ref_qualifier.
    	* parser.c (cp_parser_ref_qualifier_seq_opt): New.
    	(cp_parser_direct_declarator): Use it.
    	(make_call_declarator): Adjust.
    	(cp_parser_lambda_declarator_opt): Adjust.
    	* call.c (add_function_candidate): Handle ref-qualifier overload
    	resolution semantics.
    	(standard_conversion): Adjust.
    	* class.c (add_method, same_signature_p): Compare ref-qualifiers.
    	* decl.c (grokdeclarator): Handle ref-qualifiers.
    	(grokfndecl): Check for invalid ref-qualifiers.
    	(static_fn_type, revert_static_member_fn): Adjust.
    	* decl2.c (build_memfn_type): Handle ref-qualifiers.
    	(check_classfn): Check them.
    	(cp_reconstruct_complex_type): Retain them.
    	* error.c (dump_ref_qualifier): New.
    	(dump_type_suffix, dump_function_decl): Use it.
    	(maybe_warn_cpp0x): Handle CPP0X_REF_QUALIFIER.
    	* pt.c (tsubst, tsubst_function_type): Instantiate ref-quals.
    	(unify): Retain them.
    	* tree.c (cp_check_qualified_type): New.
    	(cp_build_qualified_type_real): Keep exception spec and ref-qual.
    	(build_ref_qualified_type): New.
    	(strip_typedefs, build_exception_variant): Keep ref-qualifier.
    	(cp_build_type_attribute_variant): Keep ref-qualifier.
    	* typeck.c (merge_types): Keep ref-qualifier.
    	(structural_comptypes): Compare ref-qualifier.
    	(type_memfn_rqual): New.
    	(apply_memfn_quals): Take ref-qual argument.
    	* typeck2.c (build_m_component_ref): Check ref-qualifier.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 5df6b47..712bd17 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1276,7 +1276,10 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
 			   static_fn_type (tofn)))
 	return NULL;
 
-      from = build_memfn_type (fromfn, tbase, cp_type_quals (tbase));
+      from = build_memfn_type (fromfn,
+                               tbase,
+                               cp_type_quals (tbase),
+                               type_memfn_rqual (tofn));
       from = build_ptrmemfunc_type (build_pointer_type (from));
       conv = build_conv (ck_pmem, from, conv);
       conv->base_p = true;
@@ -1950,7 +1953,17 @@ add_function_candidate (struct z_candidate **candidates,
 	    {
 	      parmtype = cp_build_qualified_type
 		(ctype, cp_type_quals (TREE_TYPE (parmtype)));
-	      parmtype = build_pointer_type (parmtype);
+	      if (FUNCTION_REF_QUALIFIED (TREE_TYPE (fn)))
+		{
+		  /* If the function has a ref-qualifier, the implicit
+		     object parameter has reference type.  */
+		  bool rv = FUNCTION_RVALUE_QUALIFIED (TREE_TYPE (fn));
+		  parmtype = cp_build_reference_type (parmtype, rv);
+		  arg = build_fold_indirect_ref (arg);
+		  argtype = lvalue_type (arg);
+		}
+	      else
+		parmtype = build_pointer_type (parmtype);
 	    }
 
 	  /* Core issue 899: When [copy-]initializing a temporary to be bound
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index cea8a51..54180a2 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1045,6 +1045,12 @@ add_method (tree type, tree method, tree using_decl)
 	 overloaded if any of them is a static member
 	 function declaration.
 
+	 [over.load] Member function declarations with the same name and
+	 the same parameter-type-list as well as member function template
+	 declarations with the same name, the same parameter-type-list, and
+	 the same template parameter lists cannot be overloaded if any of
+	 them, but not all, have a ref-qualifier.
+
 	 [namespace.udecl] When a using-declaration brings names
 	 from a base class into a derived class scope, member
 	 functions in the derived class override and/or hide member
@@ -1060,11 +1066,13 @@ add_method (tree type, tree method, tree using_decl)
 	 coming from the using class in overload resolution.  */
       if (! DECL_STATIC_FUNCTION_P (fn)
 	  && ! DECL_STATIC_FUNCTION_P (method)
-	  && TREE_TYPE (TREE_VALUE (parms1)) != error_mark_node
-	  && TREE_TYPE (TREE_VALUE (parms2)) != error_mark_node
-	  && (cp_type_quals (TREE_TYPE (TREE_VALUE (parms1)))
-	      != cp_type_quals (TREE_TYPE (TREE_VALUE (parms2)))))
-	continue;
+	  /* Either both or neither need to be ref-qualified for
+	     differing quals to allow overloading.  */
+	  && (FUNCTION_REF_QUALIFIED (fn_type)
+	      == FUNCTION_REF_QUALIFIED (method_type))
+	  && (type_memfn_quals (fn_type) != type_memfn_quals (method_type)
+	      || type_memfn_rqual (fn_type) != type_memfn_rqual (method_type)))
+	  continue;
 
       /* For templates, the return type and template parameters
 	 must be identical.  */
@@ -2063,6 +2071,8 @@ same_signature_p (const_tree fndecl, const_tree base_fndecl)
       base_types = TYPE_ARG_TYPES (TREE_TYPE (base_fndecl));
       if ((cp_type_quals (TREE_TYPE (TREE_VALUE (base_types)))
 	   == cp_type_quals (TREE_TYPE (TREE_VALUE (types))))
+	  && (type_memfn_rqual (TREE_TYPE (fndecl))
+	      == type_memfn_rqual (TREE_TYPE (base_fndecl)))
 	  && compparms (TREE_CHAIN (base_types), TREE_CHAIN (types)))
 	return 1;
     }
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 3119105..74ea4e4 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -107,8 +107,10 @@ c-common.h, not after.
 	  or FIELD_DECL).
       IDENTIFIER_TYPENAME_P (in IDENTIFIER_NODE)
       DECL_TINFO_P (in VAR_DECL)
+      FUNCTION_REF_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
    5: C_IS_RESERVED_WORD (in IDENTIFIER_NODE)
       DECL_VTABLE_OR_VTT_P (in VAR_DECL)
+      FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
    6: IDENTIFIER_REPO_CHOSEN (in IDENTIFIER_NODE)
       DECL_CONSTRUCTION_VTABLE_P (in VAR_DECL)
       TYPE_MARKED_P (in _TYPE)
@@ -221,6 +223,9 @@ c-common.h, not after.
 #define BOUND_TEMPLATE_TEMPLATE_PARM_TYPE_CHECK(NODE) \
   TREE_CHECK(NODE,BOUND_TEMPLATE_TEMPLATE_PARM)
 
+#define FUNCTION_OR_METHOD_TYPE_CHECK(NODE) \
+  TREE_CHECK2(NODE,FUNCTION_TYPE,METHOD_TYPE)
+
 #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
 #define THUNK_FUNCTION_CHECK(NODE) __extension__			\
 ({  __typeof (NODE) const __t = (NODE);					\
@@ -431,9 +436,11 @@ typedef enum cpp0x_warn_str
   /* inheriting constructors */
   CPP0X_INHERITING_CTORS,
   /* C++11 attributes */
-  CPP0X_ATTRIBUTES
+  CPP0X_ATTRIBUTES,
+  /* ref-qualified member functions */
+  CPP0X_REF_QUALIFIER
 } cpp0x_warn_str;
-  
+
 /* The various kinds of operation used by composite_pointer_type. */
 
 typedef enum composite_pointer_operation
@@ -2527,6 +2534,14 @@ struct GTY((variable_size)) lang_decl {
 /* 1 iff VAR_DECL node NODE is virtual table or VTT.  */
 #define DECL_VTABLE_OR_VTT_P(NODE) TREE_LANG_FLAG_5 (VAR_DECL_CHECK (NODE))
 
+/* 1 iff FUNCTION_TYPE or METHOD_TYPE has a ref-qualifier (either & or &&). */
+#define FUNCTION_REF_QUALIFIED(NODE) \
+  TREE_LANG_FLAG_4 (FUNCTION_OR_METHOD_TYPE_CHECK (NODE))
+
+/* 1 iff FUNCTION_TYPE or METHOD_TYPE has &&-ref-qualifier.  */
+#define FUNCTION_RVALUE_QUALIFIED(NODE) \
+  TREE_LANG_FLAG_5 (FUNCTION_OR_METHOD_TYPE_CHECK (NODE))
+
 /* Returns 1 iff VAR_DECL is a construction virtual table.
    DECL_VTABLE_OR_VTT_P will be true in this case and must be checked
    before using this macro.  */
@@ -4691,6 +4706,23 @@ enum virt_specifier
 
 typedef int cp_virt_specifiers;
 
+/* Wherever there is a function-cv-qual, there could also be a ref-qualifier:
+
+   [dcl.fct]
+   The return type, the parameter-type-list, the ref-qualifier, and
+   the cv-qualifier-seq, but not the default arguments or the exception
+   specification, are part of the function type.
+
+   REF_QUAL_NONE    Ordinary member function with no ref-qualifier
+   REF_QUAL_LVALUE  Member function with the &-ref-qualifier
+   REF_QUAL_RVALUE  Member function with the &&-ref-qualifier */
+
+enum cp_ref_qualifier {
+  REF_QUAL_NONE = 0,
+  REF_QUAL_LVALUE = 1,
+  REF_QUAL_RVALUE = 2
+};
+
 /* A storage class.  */
 
 typedef enum cp_storage_class {
@@ -4852,6 +4884,8 @@ struct cp_declarator {
       cp_cv_quals qualifiers;
       /* The virt-specifiers for the function.  */
       cp_virt_specifiers virt_specifiers;
+      /* The ref-qualifier for the function.  */
+      cp_ref_qualifier ref_qualifier;
       /* The exception-specification for the function.  */
       tree exception_specification;
       /* The late-specified return type, if any.  */
@@ -5202,7 +5236,8 @@ extern tree cxx_maybe_build_cleanup		(tree, tsubst_flags_t);
 
 /* in decl2.c */
 extern bool check_java_method			(tree);
-extern tree build_memfn_type			(tree, tree, cp_cv_quals);
+extern tree build_memfn_type			(tree, tree, cp_cv_quals, cp_ref_qualifier);
+extern tree build_pointer_ptrmemfn_type	(tree);
 extern tree change_return_type			(tree, tree);
 extern void maybe_retrofit_in_chrg		(tree);
 extern void maybe_make_one_only			(tree);
@@ -5809,6 +5844,7 @@ extern void diagnose_non_constexpr_vec_init	(tree);
 extern tree hash_tree_cons			(tree, tree, tree);
 extern tree hash_tree_chain			(tree, tree);
 extern tree build_qualified_name		(tree, tree, tree, bool);
+extern tree build_ref_qualified_type		(tree, cp_ref_qualifier);
 extern int is_overloaded_fn			(tree);
 extern tree dependent_name			(tree);
 extern tree get_fns				(tree);
@@ -5966,7 +6002,8 @@ extern tree build_ptrmemfunc			(tree, tree, int, bool,
 						 tsubst_flags_t);
 extern int cp_type_quals			(const_tree);
 extern int type_memfn_quals			(const_tree);
-extern tree apply_memfn_quals			(tree, cp_cv_quals);
+extern cp_ref_qualifier type_memfn_rqual	(const_tree);
+extern tree apply_memfn_quals			(tree, cp_cv_quals, cp_ref_qualifier);
 extern bool cp_has_mutable_p			(const_tree);
 extern bool at_least_as_qualified_p		(const_tree, const_tree);
 extern void cp_apply_type_quals_to_decl		(int, tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 98d30dd..9e280ea 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -7319,6 +7319,7 @@ grokfndecl (tree ctype,
 	    int virtualp,
 	    enum overload_flags flags,
 	    cp_cv_quals quals,
+	    cp_ref_qualifier rqual,
 	    tree raises,
 	    int check,
 	    int friendp,
@@ -7335,6 +7336,8 @@ grokfndecl (tree ctype,
   int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE;
   tree t;
 
+  if (rqual)
+    type = build_ref_qualified_type (type, rqual);
   if (raises)
     type = build_exception_variant (type, raises);
 
@@ -7542,13 +7545,25 @@ grokfndecl (tree ctype,
     DECL_DECLARED_CONSTEXPR_P (decl) = true;
 
   DECL_EXTERNAL (decl) = 1;
-  if (quals && TREE_CODE (type) == FUNCTION_TYPE)
+  if (TREE_CODE (type) == FUNCTION_TYPE)
     {
-      error (ctype
-             ? G_("static member function %qD cannot have cv-qualifier")
-             : G_("non-member function %qD cannot have cv-qualifier"),
-	     decl);
-      quals = TYPE_UNQUALIFIED;
+      if (quals)
+	{
+	  error (ctype
+		 ? G_("static member function %qD cannot have cv-qualifier")
+		 : G_("non-member function %qD cannot have cv-qualifier"),
+		 decl);
+	  quals = TYPE_UNQUALIFIED;
+	}
+
+      if (rqual)
+	{
+	  error (ctype
+		 ? G_("static member function %qD cannot have ref-qualifier")
+		 : G_("non-member function %qD cannot have ref-qualifier"),
+		 decl);
+	  rqual = REF_QUAL_NONE;
+	}
     }
 
   if (IDENTIFIER_OPNAME_P (DECL_NAME (decl))
@@ -7986,7 +8001,8 @@ build_ptrmem_type (tree class_type, tree member_type)
   if (TREE_CODE (member_type) == METHOD_TYPE)
     {
       cp_cv_quals quals = type_memfn_quals (member_type);
-      member_type = build_memfn_type (member_type, class_type, quals);
+      cp_ref_qualifier rqual = type_memfn_rqual (member_type);
+      member_type = build_memfn_type (member_type, class_type, quals, rqual);
       return build_ptrmemfunc_type (build_pointer_type (member_type));
     }
   else
@@ -8635,6 +8651,9 @@ grokdeclarator (const cp_declarator *declarator,
   /* virt-specifiers that apply to the declarator, for a declaration of
      a member function.  */
   cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED;
+  /* ref-qualifier that applies to the declarator, for a declaration of
+     a member function.  */
+  cp_ref_qualifier rqual = REF_QUAL_NONE;
   /* cv-qualifiers that apply to the type specified by the DECLSPECS.  */
   int type_quals;
   tree raises = NULL_TREE;
@@ -9444,6 +9463,8 @@ grokdeclarator (const cp_declarator *declarator,
 	    memfn_quals = declarator->u.function.qualifiers;
 	    /* Pick up virt-specifiers.  */
             virt_specifiers = declarator->u.function.virt_specifiers;
+	    /* And ref-qualifier, too */
+	    rqual = declarator->u.function.ref_qualifier;
 	    /* Pick up the exception specifications.  */
 	    raises = declarator->u.function.exception_specification;
 	    /* If the exception-specification is ill-formed, let's pretend
@@ -9511,12 +9532,13 @@ grokdeclarator (const cp_declarator *declarator,
 		   therefore returns a void type.  */
 
 		/* ISO C++ 12.4/2.  A destructor may not be declared
-		   const or volatile.  A destructor may not be
-		   static.
+		   const or volatile.  A destructor may not be static.
+		   A destructor may not be declared with ref-qualifier.
 
 		   ISO C++ 12.1.  A constructor may not be declared
 		   const or volatile.  A constructor may not be
-		   virtual.  A constructor may not be static.  */
+		   virtual.  A constructor may not be static.
+		   A constructor may not be declared with ref-qualifier. */
 		if (staticp == 2)
 		  error ((flags == DTOR_FLAG)
 			 ? G_("destructor cannot be static member function")
@@ -9529,6 +9551,14 @@ grokdeclarator (const cp_declarator *declarator,
 		    memfn_quals = TYPE_UNQUALIFIED;
 		  }
 
+		if (rqual)
+		  {
+		    error ((flags == DTOR_FLAG)
+			   ? "destructors may not be ref-qualified"
+			   : "constructors may not be ref-qualified");
+		    rqual = REF_QUAL_NONE;
+		  }
+
 		if (decl_context == FIELD
 		    && !member_function_or_else (ctype,
 						 current_class_type,
@@ -9650,14 +9680,18 @@ grokdeclarator (const cp_declarator *declarator,
 	      memfn_quals |= type_memfn_quals (type);
 	      type = build_memfn_type (type,
 				       declarator->u.pointer.class_type,
-				       memfn_quals);
+				       memfn_quals,
+				       rqual);
 	      if (type == error_mark_node)
 		return error_mark_node;
+
+	      rqual = REF_QUAL_NONE;
 	      memfn_quals = TYPE_UNQUALIFIED;
 	    }
 
 	  if (TREE_CODE (type) == FUNCTION_TYPE
-	      && type_memfn_quals (type) != TYPE_UNQUALIFIED)
+	      && (type_memfn_quals (type) != TYPE_UNQUALIFIED
+		  || type_memfn_rqual (type) != REF_QUAL_NONE))
             error (declarator->kind == cdk_reference
                    ? G_("cannot declare reference to qualified function type %qT")
                    : G_("cannot declare pointer to qualified function type %qT"),
@@ -10002,12 +10036,13 @@ grokdeclarator (const cp_declarator *declarator,
 	 example "f S::*" declares a pointer to a const-qualified
 	 member function of S.  We record the cv-qualification in the
 	 function type.  */
-      if (memfn_quals && TREE_CODE (type) == FUNCTION_TYPE)
+      if ((rqual || memfn_quals) && TREE_CODE (type) == FUNCTION_TYPE)
         {
-          type = apply_memfn_quals (type, memfn_quals);
+          type = apply_memfn_quals (type, memfn_quals, rqual);
           
           /* We have now dealt with these qualifiers.  */
           memfn_quals = TYPE_UNQUALIFIED;
+	  rqual = REF_QUAL_NONE;
         }
 
       if (type_uses_auto (type))
@@ -10137,8 +10172,10 @@ grokdeclarator (const cp_declarator *declarator,
       if (decl_context != TYPENAME)
 	{
 	  /* A cv-qualifier-seq shall only be part of the function type
-	     for a non-static member function. [8.3.5/4 dcl.fct] */
-	  if (type_memfn_quals (type) != TYPE_UNQUALIFIED
+	     for a non-static member function. A ref-qualifier shall only
+	     .... /same as above/ [dcl.fct] */
+	  if ((type_memfn_quals (type) != TYPE_UNQUALIFIED
+	       || type_memfn_rqual (type) != REF_QUAL_NONE)
 	      && (current_class_type == NULL_TREE || staticp) )
 	    {
 	      error (staticp
@@ -10152,6 +10189,7 @@ grokdeclarator (const cp_declarator *declarator,
 	  /* The qualifiers on the function type become the qualifiers on
 	     the non-static member function. */
 	  memfn_quals |= type_memfn_quals (type);
+	  rqual = type_memfn_rqual (type);
 	  type_quals = TYPE_UNQUALIFIED;
 	}
     }
@@ -10216,10 +10254,10 @@ grokdeclarator (const cp_declarator *declarator,
 	    ctype = TYPE_METHOD_BASETYPE (type);
 
 	  if (ctype)
-	    type = build_memfn_type (type, ctype, memfn_quals);
+	    type = build_memfn_type (type, ctype, memfn_quals, rqual);
 	  /* Core issue #547: need to allow this in template type args.  */
 	  else if (template_type_arg && TREE_CODE (type) == FUNCTION_TYPE)
-	    type = apply_memfn_quals (type, memfn_quals);
+	    type = apply_memfn_quals (type, memfn_quals, rqual);
 	  else
 	    error ("invalid qualifiers on non-member function type");
 	}
@@ -10288,7 +10326,7 @@ grokdeclarator (const cp_declarator *declarator,
       cp_cv_quals real_quals = memfn_quals;
       if (constexpr_p && sfk != sfk_constructor && sfk != sfk_destructor)
 	real_quals |= TYPE_QUAL_CONST;
-      type = build_memfn_type (type, ctype, real_quals);
+      type = build_memfn_type (type, ctype, real_quals, rqual);
     }
 
   {
@@ -10420,7 +10458,7 @@ grokdeclarator (const cp_declarator *declarator,
 			       ? unqualified_id : dname,
 			       parms,
 			       unqualified_id,
-			       virtualp, flags, memfn_quals, raises,
+			       virtualp, flags, memfn_quals, rqual, raises,
 			       friendp ? -1 : 0, friendp, publicp,
                                inlinep | (2 * constexpr_p),
 			       sfk,
@@ -10641,7 +10679,7 @@ grokdeclarator (const cp_declarator *declarator,
 		   || storage_class != sc_static);
 
 	decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
-			   virtualp, flags, memfn_quals, raises,
+			   virtualp, flags, memfn_quals, rqual, raises,
 			   1, friendp,
 			   publicp, inlinep | (2 * constexpr_p), sfk,
                            funcdef_flag,
@@ -14216,8 +14254,9 @@ static_fn_type (tree memfntype)
     return memfntype;
   gcc_assert (TREE_CODE (memfntype) == METHOD_TYPE);
   args = TYPE_ARG_TYPES (memfntype);
+  cp_ref_qualifier rqual = type_memfn_rqual (memfntype);
   fntype = build_function_type (TREE_TYPE (memfntype), TREE_CHAIN (args));
-  fntype = apply_memfn_quals (fntype, type_memfn_quals (memfntype));
+  fntype = apply_memfn_quals (fntype, type_memfn_quals (memfntype), rqual);
   fntype = (cp_build_type_attribute_variant
 	    (fntype, TYPE_ATTRIBUTES (memfntype)));
   fntype = (build_exception_variant
@@ -14233,9 +14272,10 @@ revert_static_member_fn (tree decl)
 {
   tree stype = static_fn_type (decl);
   cp_cv_quals quals = type_memfn_quals (stype);
+  cp_ref_qualifier rqual = type_memfn_rqual (stype);
 
-  if (quals != TYPE_UNQUALIFIED)
-    stype = apply_memfn_quals (stype, TYPE_UNQUALIFIED);
+  if (quals != TYPE_UNQUALIFIED || rqual != REF_QUAL_NONE)
+    stype = apply_memfn_quals (stype, TYPE_UNQUALIFIED, REF_QUAL_NONE);
 
   TREE_TYPE (decl) = stype;
 
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index e14c388..ef1f1e7 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -109,7 +109,8 @@ int at_eof;
    that apply to the function).  */
 
 tree
-build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals)
+build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals,
+		  cp_ref_qualifier rqual)
 {
   tree raises;
   tree attrs;
@@ -129,10 +130,12 @@ build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals)
 				       (TREE_CODE (fntype) == METHOD_TYPE
 					? TREE_CHAIN (TYPE_ARG_TYPES (fntype))
 					: TYPE_ARG_TYPES (fntype)));
-  if (raises)
-    fntype = build_exception_variant (fntype, raises);
   if (attrs)
     fntype = cp_build_type_attribute_variant (fntype, attrs);
+  if (rqual)
+    fntype = build_ref_qualified_type (fntype, rqual);
+  if (raises)
+    fntype = build_exception_variant (fntype, raises);
 
   return fntype;
 }
@@ -157,7 +160,9 @@ change_return_type (tree new_ret, tree fntype)
   if (TREE_CODE (fntype) == FUNCTION_TYPE)
     {
       newtype = build_function_type (new_ret, args);
-      newtype = apply_memfn_quals (newtype, type_memfn_quals (fntype));
+      newtype = apply_memfn_quals (newtype,
+				   type_memfn_quals (fntype),
+				   type_memfn_rqual (fntype));
     }
   else
     newtype = build_method_type_directly
@@ -672,6 +677,11 @@ check_classfn (tree ctype, tree function, tree template_parms)
 	  if (is_template != (TREE_CODE (fndecl) == TEMPLATE_DECL))
 	    continue;
 
+	  /* ref-qualifier or absence of same must match.  */
+	  if (type_memfn_rqual (TREE_TYPE (function))
+	      != type_memfn_rqual (TREE_TYPE (fndecl)))
+	    continue;
+
 	  /* While finding a match, same types and params are not enough
 	     if the function is versioned.  Also check version ("target")
 	     attributes.  */
@@ -1260,7 +1270,9 @@ cp_reconstruct_complex_type (tree type, tree bottom)
     {
       inner = cp_reconstruct_complex_type (TREE_TYPE (type), bottom);
       outer = build_function_type (inner, TYPE_ARG_TYPES (type));
-      outer = apply_memfn_quals (outer, type_memfn_quals (type));
+      outer = apply_memfn_quals (outer,
+				 type_memfn_quals (type),
+				 type_memfn_rqual (type));
     }
   else if (TREE_CODE (type) == METHOD_TYPE)
     {
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 38da243..6df8987 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -78,6 +78,7 @@ static void dump_aggr_init_expr_args (tree, int, bool);
 static void dump_expr_list (tree, int);
 static void dump_global_iord (tree);
 static void dump_parameters (tree, int);
+static void dump_ref_qualifier (tree, int);
 static void dump_exception_spec (tree, int);
 static void dump_template_argument (tree, int);
 static void dump_template_argument_list (tree, int);
@@ -832,6 +833,7 @@ dump_type_suffix (tree t, int flags)
 	  pp_cxx_cv_qualifier_seq (cxx_pp, class_of_this_parm (t));
 	else
 	  pp_cxx_cv_qualifier_seq (cxx_pp, t);
+	dump_ref_qualifier (t, flags);
 	dump_exception_spec (TYPE_RAISES_EXCEPTIONS (t), flags);
 	dump_type_suffix (TREE_TYPE (t), flags);
 	break;
@@ -1426,6 +1428,7 @@ dump_function_decl (tree t, int flags)
 	{
 	  pp_base (cxx_pp)->padding = pp_before;
 	  pp_cxx_cv_qualifier_seq (cxx_pp, class_of_this_parm (fntype));
+	  dump_ref_qualifier (fntype, flags);
 	}
 
       if (flags & TFF_EXCEPTION_SPECIFICATION)
@@ -1507,6 +1510,21 @@ dump_parameters (tree parmtypes, int flags)
   pp_cxx_right_paren (cxx_pp);
 }
 
+/* Print ref-qualifier of a FUNCTION_TYPE or METHOD_TYPE. FLAGS are ignored. */
+
+static void
+dump_ref_qualifier (tree t, int flags ATTRIBUTE_UNUSED)
+{
+  if (FUNCTION_REF_QUALIFIED (t))
+    {
+      pp_base (cxx_pp)->padding = pp_before;
+      if (FUNCTION_RVALUE_QUALIFIED (t))
+        pp_cxx_ws_string (cxx_pp, "&&");
+      else
+        pp_cxx_ws_string (cxx_pp, "&");
+    }
+}
+
 /* Print an exception specification. T is the exception specification.  */
 
 static void
@@ -3408,6 +3426,11 @@ maybe_warn_cpp0x (cpp0x_warn_str str)
 		 "c++11 attributes "
 		 "only available with -std=c++11 or -std=gnu++11");
 	break;
+      case CPP0X_REF_QUALIFIER:
+	pedwarn (input_location, 0,
+		 "ref-qualifiers "
+		 "only available with -std=c++0x or -std=gnu++0x");
+	break;
       default:
 	gcc_unreachable ();
       }
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index a5cf66d..f29e80d 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1234,7 +1234,7 @@ clear_decl_specs (cp_decl_specifier_seq *decl_specs)
    VAR_DECLs or FUNCTION_DECLs) should do that directly.  */
 
 static cp_declarator *make_call_declarator
-  (cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, tree, tree);
+  (cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, cp_ref_qualifier, tree, tree);
 static cp_declarator *make_array_declarator
   (cp_declarator *, tree);
 static cp_declarator *make_pointer_declarator
@@ -1413,6 +1413,7 @@ make_call_declarator (cp_declarator *target,
 		      tree parms,
 		      cp_cv_quals cv_qualifiers,
 		      cp_virt_specifiers virt_specifiers,
+		      cp_ref_qualifier ref_qualifier,
 		      tree exception_specification,
 		      tree late_return_type)
 {
@@ -1423,6 +1424,7 @@ make_call_declarator (cp_declarator *target,
   declarator->u.function.parameters = parms;
   declarator->u.function.qualifiers = cv_qualifiers;
   declarator->u.function.virt_specifiers = virt_specifiers;
+  declarator->u.function.ref_qualifier = ref_qualifier;
   declarator->u.function.exception_specification = exception_specification;
   declarator->u.function.late_return_type = late_return_type;
   if (target)
@@ -2018,6 +2020,8 @@ static cp_cv_quals cp_parser_cv_qualifier_seq_opt
   (cp_parser *);
 static cp_virt_specifiers cp_parser_virt_specifier_seq_opt
   (cp_parser *);
+static cp_ref_qualifier cp_parser_ref_qualifier_seq_opt
+  (cp_parser *);
 static tree cp_parser_late_return_type_opt
   (cp_parser *, cp_cv_quals);
 static tree cp_parser_declarator_id
@@ -8640,6 +8644,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 	     ? TYPE_UNQUALIFIED : TYPE_QUAL_CONST);
     declarator = make_call_declarator (declarator, param_list, quals,
 				       VIRT_SPEC_UNSPECIFIED,
+                                       REF_QUAL_NONE,
 				       exception_spec,
                                        /*late_return_type=*/NULL_TREE);
     declarator->id_loc = LAMBDA_EXPR_LOCATION (lambda_expr);
@@ -16309,6 +16314,7 @@ cp_parser_declarator (cp_parser* parser,
      declarator-id
      direct-declarator ( parameter-declaration-clause )
        cv-qualifier-seq [opt]
+       ref-qualifier [opt]
        exception-specification [opt]
      direct-declarator [ constant-expression [opt] ]
      ( declarator )
@@ -16317,6 +16323,7 @@ cp_parser_declarator (cp_parser* parser,
      direct-abstract-declarator [opt]
        ( parameter-declaration-clause )
        cv-qualifier-seq [opt]
+       ref-qualifier [opt]
        exception-specification [opt]
      direct-abstract-declarator [opt] [ constant-expression [opt] ]
      ( abstract-declarator )
@@ -16431,12 +16438,13 @@ cp_parser_direct_declarator (cp_parser* parser,
 	      /* Consume the `)'.  */
 	      cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
 
-	      /* If all went well, parse the cv-qualifier-seq and the
-		 exception-specification.  */
+	      /* If all went well, parse the cv-qualifier-seq,
+		 ref-qualifier and the exception-specification.  */
 	      if (member_p || cp_parser_parse_definitely (parser))
 		{
 		  cp_cv_quals cv_quals;
 		  cp_virt_specifiers virt_specifiers;
+		  cp_ref_qualifier ref_qual;
 		  tree exception_specification;
 		  tree late_return;
 		  tree attrs;
@@ -16451,6 +16459,8 @@ cp_parser_direct_declarator (cp_parser* parser,
 
 		  /* Parse the cv-qualifier-seq.  */
 		  cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
+		  /* Parse the ref-qualifier. */
+		  ref_qual = cp_parser_ref_qualifier_seq_opt (parser);
 		  /* And the exception-specification.  */
 		  exception_specification
 		    = cp_parser_exception_specification_opt (parser);
@@ -16468,6 +16478,7 @@ cp_parser_direct_declarator (cp_parser* parser,
 						     params,
 						     cv_quals,
 						     virt_specifiers,
+						     ref_qual,
 						     exception_specification,
 						     late_return);
 		  declarator->std_attributes = attrs;
@@ -17008,6 +17019,38 @@ cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
   return cv_quals;
 }
 
+/* Parse an (optional) ref-qualifier
+
+   ref-qualifier:
+     &
+     &&
+
+   Returns cp_ref_qualifier representing ref-qualifier. */
+
+static cp_ref_qualifier
+cp_parser_ref_qualifier_seq_opt (cp_parser* parser)
+{
+  cp_ref_qualifier ref_qual = REF_QUAL_NONE;
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+  switch (token->type)
+    {
+    case CPP_AND:
+      ref_qual = REF_QUAL_LVALUE;
+      break;
+    case CPP_AND_AND:
+      ref_qual = REF_QUAL_RVALUE;
+      break;
+    }
+
+  if (ref_qual)
+    {
+      maybe_warn_cpp0x (CPP0X_REF_QUALIFIER);
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  return ref_qual;
+}
+
 /* Parse an (optional) virt-specifier-seq.
 
    virt-specifier-seq:
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7f4212d..d143256 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10955,7 +10955,9 @@ tsubst_function_type (tree t,
   if (TREE_CODE (t) == FUNCTION_TYPE)
     {
       fntype = build_function_type (return_type, arg_types);
-      fntype = apply_memfn_quals (fntype, type_memfn_quals (t));
+      fntype = apply_memfn_quals (fntype,
+				  type_memfn_quals (t),
+				  type_memfn_rqual (t));
     }
   else
     {
@@ -10977,6 +10979,7 @@ tsubst_function_type (tree t,
 
       fntype = build_method_type_directly (r, return_type,
 					   TREE_CHAIN (arg_types));
+      fntype = build_ref_qualified_type (fntype, type_memfn_rqual (t));
     }
   fntype = cp_build_type_attribute_variant (fntype, TYPE_ATTRIBUTES (t));
 
@@ -11609,7 +11612,9 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	    /* The type of the implicit object parameter gets its
 	       cv-qualifiers from the FUNCTION_TYPE. */
 	    tree memptr;
-	    tree method_type = build_memfn_type (type, r, type_memfn_quals (type));
+	    tree method_type
+	      = build_memfn_type (type, r, type_memfn_quals (type),
+				  type_memfn_rqual (type));
 	    memptr = build_ptrmemfunc_type (build_pointer_type (method_type));
 	    return cp_build_qualified_type_real (memptr, cp_type_quals (t),
 						 complain);
@@ -17097,10 +17102,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 	    build_function_type (TREE_TYPE (method_type),
 				 TREE_CHAIN (TYPE_ARG_TYPES (method_type)));
 
-	  /* Extract the cv-qualifiers of the member function from the
-	     implicit object parameter and place them on the function
-	     type to be restored later. */
-	  fntype = apply_memfn_quals (fntype, type_memfn_quals (method_type));
+	  /* Extract the cv-qualifiers and ref-qualifier of the member
+	     function from the implicit object parameter and place them
+	     on the function type to be restored later. */
+	  fntype = apply_memfn_quals (fntype,
+				      type_memfn_quals (method_type),
+				      type_memfn_rqual (method_type));
 	  return unify (tparms, targs, TREE_TYPE (parm), fntype, strict, explain_p);
 	}
 
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 7fb8698..ce9568c 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1081,6 +1081,15 @@ cp_build_qualified_type_real (tree type,
   /* Retrieve (or create) the appropriately qualified variant.  */
   result = build_qualified_type (type, type_quals);
 
+  /* Preserve exception specs and ref-qualifier since build_qualified_type
+     doesn't know about them.  */
+  if (TREE_CODE (result) == FUNCTION_TYPE
+      || TREE_CODE (result) == METHOD_TYPE)
+    {
+      result = build_exception_variant (result, TYPE_RAISES_EXCEPTIONS (type));
+      result = build_ref_qualified_type (result, type_memfn_rqual (type));
+    }
+
   /* If this was a pointer-to-method type, and we just made a copy,
      then we need to unshare the record that holds the cached
      pointer-to-member-function type, because these will be distinct
@@ -1214,7 +1223,9 @@ strip_typedefs (tree t)
 	  {
 	    result = build_function_type (type,
 					  arg_types);
-	    result = apply_memfn_quals (result, type_memfn_quals (t));
+	    result = apply_memfn_quals (result,
+					type_memfn_quals (t),
+					type_memfn_rqual (t));
 	  }
 
 	if (TYPE_RAISES_EXCEPTIONS (t))
@@ -1702,6 +1713,64 @@ build_qualified_name (tree type, tree scope, tree name, bool template_p)
   return t;
 }
 
+/* Like check_qualified_type, but also check ref-qualifier and exception
+   specification.  */
+
+static bool
+cp_check_qualified_type (const_tree cand, const_tree base, int type_quals,
+			 cp_ref_qualifier rqual, tree raises)
+{
+  return (check_qualified_type (cand, base, type_quals)
+	  && comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (cand),
+				ce_exact)
+	  && type_memfn_rqual (cand) == rqual);
+}
+
+/* Build the FUNCTION_TYPE or METHOD_TYPE with the ref-qualifier RQUAL.  */
+
+tree
+build_ref_qualified_type (tree type, cp_ref_qualifier rqual)
+{
+  tree t;
+
+  if (rqual == type_memfn_rqual (type))
+    return type;
+
+  int type_quals = TYPE_QUALS (type);
+  tree raises = TYPE_RAISES_EXCEPTIONS (type);
+  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+    if (cp_check_qualified_type (t, type, type_quals, rqual, raises))
+      return t;
+
+  t = build_variant_type_copy (type);
+  switch (rqual)
+    {
+    case REF_QUAL_RVALUE:
+      FUNCTION_RVALUE_QUALIFIED (t) = 1;
+      /* Intentional fall through */
+    case REF_QUAL_LVALUE:
+      FUNCTION_REF_QUALIFIED (t) = 1;
+      break;
+    default:
+      FUNCTION_REF_QUALIFIED (t) = 0;
+      break;
+    }
+
+  if (TYPE_STRUCTURAL_EQUALITY_P (type))
+    /* Propagate structural equality. */
+    SET_TYPE_STRUCTURAL_EQUALITY (t);
+  else if (TYPE_CANONICAL (type) != type)
+    /* Build the underlying canonical type, since it is different
+       from TYPE. */
+    TYPE_CANONICAL (t) = build_ref_qualified_type (TYPE_CANONICAL (type),
+						   rqual);
+  else
+    /* T is its own canonical type. */
+    TYPE_CANONICAL (t) = t;
+
+  return t;
+}
+
 /* Returns nonzero if X is an expression for a (possibly overloaded)
    function.  If "f" is a function or function template, "f", "c->f",
    "c.f", "C::f", and "f<int>" will all be considered possibly
@@ -1907,9 +1976,9 @@ build_exception_variant (tree type, tree raises)
     return type;
 
   type_quals = TYPE_QUALS (type);
+  cp_ref_qualifier rqual = type_memfn_rqual (type);
   for (v = TYPE_MAIN_VARIANT (type); v; v = TYPE_NEXT_VARIANT (v))
-    if (check_qualified_type (v, type, type_quals)
-	&& comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (v), ce_exact))
+    if (cp_check_qualified_type (v, type, type_quals, rqual, raises))
       return v;
 
   /* Need to build a new variant.  */
@@ -3308,8 +3377,12 @@ cp_build_type_attribute_variant (tree type, tree attributes)
   new_type = build_type_attribute_variant (type, attributes);
   if (TREE_CODE (new_type) == FUNCTION_TYPE
       || TREE_CODE (new_type) == METHOD_TYPE)
-    new_type = build_exception_variant (new_type,
-					TYPE_RAISES_EXCEPTIONS (type));
+    {
+      new_type = build_exception_variant (new_type,
+					  TYPE_RAISES_EXCEPTIONS (type));
+      new_type = build_ref_qualified_type (new_type,
+					   type_memfn_rqual (type));
+    }
 
   /* Making a new main variant of a class type is broken.  */
   gcc_assert (!CLASS_TYPE_P (type) || new_type == type);
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index ae92675..763fc0b 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -832,7 +832,10 @@ merge_types (tree t1, tree t2)
 
 	rval = build_function_type (valtype, parms);
 	gcc_assert (type_memfn_quals (t1) == type_memfn_quals (t2));
-	rval = apply_memfn_quals (rval, type_memfn_quals (t1));
+	gcc_assert (type_memfn_rqual (t1) == type_memfn_rqual (t2));
+	rval = apply_memfn_quals (rval,
+				  type_memfn_quals (t1),
+				  type_memfn_rqual (t1));
 	raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
 					     TYPE_RAISES_EXCEPTIONS (t2),
 					     NULL_TREE);
@@ -1184,6 +1187,12 @@ structural_comptypes (tree t1, tree t2, int strict)
   if (TREE_CODE (t1) == FUNCTION_TYPE
       && type_memfn_quals (t1) != type_memfn_quals (t2))
     return false;
+  /* Need to check this before TYPE_MAIN_VARIANT.
+     FIXME function qualifiers should really change the main variant.  */
+  if ((TREE_CODE (t1) == FUNCTION_TYPE
+       || TREE_CODE (t1) == METHOD_TYPE)
+      && type_memfn_rqual (t1) != type_memfn_rqual (t2))
+    return false;
   if (TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2))
     return false;
 
@@ -8563,6 +8572,22 @@ cp_type_quals (const_tree type)
   return quals;
 }
 
+/* Returns the function-ref-qualifier for TYPE */
+
+cp_ref_qualifier
+type_memfn_rqual (const_tree type)
+{
+  gcc_assert (TREE_CODE (type) == FUNCTION_TYPE
+              || TREE_CODE (type) == METHOD_TYPE);
+
+  if (!FUNCTION_REF_QUALIFIED (type))
+    return REF_QUAL_NONE;
+  else if (FUNCTION_RVALUE_QUALIFIED (type))
+    return REF_QUAL_RVALUE;
+  else
+    return REF_QUAL_LVALUE;
+}
+
 /* Returns the function-cv-quals for TYPE, which must be a FUNCTION_TYPE or
    METHOD_TYPE.  */
 
@@ -8578,18 +8603,22 @@ type_memfn_quals (const_tree type)
 }
 
 /* Returns the FUNCTION_TYPE TYPE with its function-cv-quals changed to
-   MEMFN_QUALS.  */
+   MEMFN_QUALS and its ref-qualifier to RQUAL. */
 
 tree
-apply_memfn_quals (tree type, cp_cv_quals memfn_quals)
+apply_memfn_quals (tree type, cp_cv_quals memfn_quals, cp_ref_qualifier rqual)
 {
   /* Could handle METHOD_TYPE here if necessary.  */
   gcc_assert (TREE_CODE (type) == FUNCTION_TYPE);
-  if (TYPE_QUALS (type) == memfn_quals)
+  if (TYPE_QUALS (type) == memfn_quals
+      && type_memfn_rqual (type) == rqual)
     return type;
+
   /* This should really have a different TYPE_MAIN_VARIANT, but that gets
      complex.  */
-  return build_qualified_type (type, memfn_quals);
+  tree result = build_qualified_type (type, memfn_quals);
+  result = build_exception_variant (result, TYPE_RAISES_EXCEPTIONS (type));
+  return build_ref_qualified_type (result, rqual);
 }
 
 /* Returns nonzero if TYPE is const or volatile.  */
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 61ec4b5..d9efafb 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1708,7 +1708,24 @@ build_m_component_ref (tree datum, tree component, tsubst_flags_t complain)
       return datum;
     }
   else
-    return build2 (OFFSET_REF, type, datum, component);
+    {
+      /* 5.5/6: In a .* expression whose object expression is an rvalue, the
+	 program is ill-formed if the second operand is a pointer to member
+	 function with ref-qualifier &. In a .* expression whose object
+	 expression is an lvalue, the program is ill-formed if the second
+	 operand is a pointer to member function with ref-qualifier &&.  */
+      if (FUNCTION_REF_QUALIFIED (type))
+	{
+	  bool lval = real_lvalue_p (datum);
+	  if (lval && FUNCTION_RVALUE_QUALIFIED (type))
+	    error ("pointer-to-member-function type %qT requires an rvalue",
+		   ptrmem_type);
+	  else if (!lval && !FUNCTION_RVALUE_QUALIFIED (type))
+	    error ("pointer-to-member-function type %qT requires an lvalue",
+		   ptrmem_type);
+	}
+      return build2 (OFFSET_REF, type, datum, component);
+    }
 }
 
 /* Return a tree node for the expression TYPENAME '(' PARMS ')'.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-qual1.C b/gcc/testsuite/g++.dg/cpp0x/ref-qual1.C
new file mode 100644
index 0000000..7fa826c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/ref-qual1.C
@@ -0,0 +1,30 @@
+// { dg-require-effective-target c++11 }
+
+template <class,class> struct ST;
+template <class T> struct ST<T,T> {};
+
+struct A
+{
+  int f() &;
+  char f() &&;
+};
+
+template <class T> struct B
+{
+  int f() &;
+  char f() &&;
+};
+
+int main()
+{
+  A a;
+  a.f();
+  A().f();
+  ST<decltype(a.f()), int>();
+  ST<decltype(A().f()), char>();
+  B<int> b;
+  b.f();
+  B<int>().f();
+  ST<decltype(b.f()), int>();
+  ST<decltype(B<int>().f()), char>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-qual2.C b/gcc/testsuite/g++.dg/cpp0x/ref-qual2.C
new file mode 100644
index 0000000..fa09ab4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/ref-qual2.C
@@ -0,0 +1,75 @@
+// In a .* expression whose object expression is an rvalue, the program is
+// ill-formed if the second operand is a pointer to member function with
+// ref-qualifier &. In a .* expression whose object expression is an
+// lvalue, the program is ill-formed if the second operand is a pointer to
+// member function with ref-qualifier &&.
+
+// { dg-require-effective-target c++11 }
+
+struct A {
+  void f() &;
+  void g() &&;
+  void h();
+};
+
+void one()
+{
+  A a;
+
+  void (A::*p)() & = &A::f;
+  (a.*p)();
+  (A().*p)();			// { dg-error "" }
+
+  p = &A::g;			// { dg-error "" }
+  p = &A::h;			// { dg-error "" }
+
+  void (A::*p2)() && = &A::g;
+  (A().*p2)();
+  (a.*p2)();			// { dg-error "" }
+  p2 = &A::f;			// { dg-error "" }
+  p2 = &A::h;			// { dg-error "" }
+
+  void (A::*p3)() = &A::h;
+  (a.*p3)();
+  (A().*p3)();
+  p3 = &A::f;			// { dg-error "" }
+  p3 = &A::g;			// { dg-error "" }
+}
+
+template <class T>
+struct B {
+  void f() &;
+  void g() &&;
+  void h();
+};
+
+template <class T>
+void two()
+{
+  B<T> a;
+
+  void (B<T>::*p)() & = &B<T>::f;
+  (a.*p)();
+  (B<T>().*p)();		// { dg-error "" }
+
+  p = &B<T>::g;			// { dg-error "" }
+  p = &B<T>::h;			// { dg-error "" }
+
+  void (B<T>::*p2)() && = &B<T>::g;
+  (B<T>().*p2)();
+  (a.*p2)();			// { dg-error "" }
+  p2 = &B<T>::f;		// { dg-error "" }
+  p2 = &B<T>::h;		// { dg-error "" }
+
+  void (B<T>::*p3)() = &B<T>::h;
+  (a.*p3)();
+  (B<T>().*p3)();
+  p3 = &B<T>::f;		// { dg-error "" }
+  p3 = &B<T>::g;		// { dg-error "" }
+}
+
+int main()
+{
+  one();
+  two<int>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-qual3.C b/gcc/testsuite/g++.dg/cpp0x/ref-qual3.C
new file mode 100644
index 0000000..1b21196
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/ref-qual3.C
@@ -0,0 +1,29 @@
+// An explicitly defaulted function can have a ref-qualifier.
+
+// { dg-require-effective-target c++11 }
+
+struct A {
+  A& operator=(const A&) & = default;
+};
+
+template<class T>
+struct B {
+  B& operator=(const B&) & = default;
+};
+
+template<class T>
+void f()
+{
+  B<T> b;
+  b = B<T>();
+  B<T>() = b;			// { dg-error "" }
+}
+
+int main()
+{
+  A a;
+  a = A();
+  A() = a;			// { dg-error "" }
+
+  f<int>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-qual4.C b/gcc/testsuite/g++.dg/cpp0x/ref-qual4.C
new file mode 100644
index 0000000..5a0ee16
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/ref-qual4.C
@@ -0,0 +1,14 @@
+// 12.1: A constructor shall not be declared with a ref-qualifier.
+// 12.4: A destructor shall not be declared with a ref-qualifier.
+
+// { dg-require-effective-target c++11 }
+
+struct A {
+  A() & = default;		// { dg-error "constructor" }
+  ~A() & = default;		// { dg-error "destructor" }
+};
+
+int main()
+{
+  A a;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-qual5.C b/gcc/testsuite/g++.dg/cpp0x/ref-qual5.C
new file mode 100644
index 0000000..e3d26e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/ref-qual5.C
@@ -0,0 +1,13 @@
+// 13.1: ...cannot be overloaded if any of them, but not all, have a
+// ref-qualifier.
+
+// { dg-require-effective-target c++11 }
+
+class Y {
+  void h() &;
+  void h() const &;	       // OK
+  void h() &&;		       // OK, all declarations have a ref-qualifier
+  void i() &;		       // { dg-message "" }
+  void i() const;	       // { dg-error "" } prior declaration of i
+			       // has a ref-qualifier
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-qual6.C b/gcc/testsuite/g++.dg/cpp0x/ref-qual6.C
new file mode 100644
index 0000000..02e3f6e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/ref-qual6.C
@@ -0,0 +1,15 @@
+// Binding an rvalue to && beats binding it to const& (13.3.3.2).
+
+// { dg-require-effective-target c++11 }
+
+struct A
+{
+  int operator+(int) &&;
+};
+
+void operator+ (const A&, int);
+
+int main()
+{
+  return A() + 42;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-qual7.C b/gcc/testsuite/g++.dg/cpp0x/ref-qual7.C
new file mode 100644
index 0000000..2430665
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/ref-qual7.C
@@ -0,0 +1,19 @@
+// typedef test
+// { dg-require-effective-target c++11 }
+
+typedef void F() &;
+
+F f;				// { dg-error "" }
+F* p;				// { dg-error "" }
+extern F& r;			// { dg-error "" }
+
+struct A {
+  F f;
+};
+
+int main()
+{
+  A a;
+  a.f();
+  A().f();			// { dg-error "" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/ref-qual8.C b/gcc/testsuite/g++.dg/cpp0x/ref-qual8.C
new file mode 100644
index 0000000..b4c972b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/ref-qual8.C
@@ -0,0 +1,13 @@
+// { dg-require-effective-target c++11 }
+
+struct A
+{
+  virtual void f() & = 0;
+};
+
+struct B: A
+{
+  void f();			// doesn't override
+};
+
+B b;				// { dg-error "abstract" }

commit f9aef3ebd305a8c1f473f300025f1dcc9fbe4fbf
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Apr 1 13:45:05 2013 -0400

    	* cxx-pretty-print.h (pp_cxx_cv_qualifiers): New.
    	* class.c (same_signature_p): Use type_memfn_quals.
    	* cp-tree.h (TYPE_RAISES_EXCEPTIONS): Use
    	FUNCTION_OR_METHOD_TYPE_CHECK.
    	* error.c (dump_type_suffix): Add padding before cv-qualifiers.
    	* pt.c (unify): Use static_fn_type.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 54180a2..6ac9a36 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -2066,14 +2066,12 @@ same_signature_p (const_tree fndecl, const_tree base_fndecl)
 	  && same_type_p (DECL_CONV_FN_TYPE (fndecl),
 			  DECL_CONV_FN_TYPE (base_fndecl))))
     {
-      tree types, base_types;
-      types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
-      base_types = TYPE_ARG_TYPES (TREE_TYPE (base_fndecl));
-      if ((cp_type_quals (TREE_TYPE (TREE_VALUE (base_types)))
-	   == cp_type_quals (TREE_TYPE (TREE_VALUE (types))))
-	  && (type_memfn_rqual (TREE_TYPE (fndecl))
-	      == type_memfn_rqual (TREE_TYPE (base_fndecl)))
-	  && compparms (TREE_CHAIN (base_types), TREE_CHAIN (types)))
+      tree fntype = TREE_TYPE (fndecl);
+      tree base_fntype = TREE_TYPE (base_fndecl);
+      if (type_memfn_quals (fntype) == type_memfn_quals (base_fntype)
+	  && type_memfn_rqual (fntype) == type_memfn_rqual (base_fntype)
+	  && compparms (FUNCTION_FIRST_USER_PARMTYPE (fndecl),
+			FUNCTION_FIRST_USER_PARMTYPE (base_fndecl)))
 	return 1;
     }
   return 0;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 74ea4e4..08a6461 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1888,7 +1888,8 @@ struct GTY((variable_size)) lang_type {
    a deferred noexcept-specification, TREE_PURPOSE is a DEFERRED_NOEXCEPT
    (for templates) or an OVERLOAD list of functions (for implicitly
    declared functions).  */
-#define TYPE_RAISES_EXCEPTIONS(NODE) TYPE_LANG_SLOT_1 (NODE)
+#define TYPE_RAISES_EXCEPTIONS(NODE) \
+  TYPE_LANG_SLOT_1 (FUNCTION_OR_METHOD_TYPE_CHECK (NODE))
 
 /* For FUNCTION_TYPE or METHOD_TYPE, return 1 iff it is declared `throw()'
    or noexcept(true).  */
diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
index f1ab0e6..0f7dc4a 100644
--- a/gcc/cp/cxx-pretty-print.h
+++ b/gcc/cp/cxx-pretty-print.h
@@ -42,6 +42,8 @@ typedef struct
 
 #define pp_cxx_cv_qualifier_seq(PP, T)   \
    pp_c_type_qualifier_list (pp_c_base (PP), T)
+#define pp_cxx_cv_qualifiers(PP, CV)   \
+   pp_c_cv_qualifiers (pp_c_base (PP), CV, false)
 
 #define pp_cxx_whitespace(PP)		pp_c_whitespace (pp_c_base (PP))
 #define pp_cxx_left_paren(PP)		pp_c_left_paren (pp_c_base (PP))
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 6df8987..c599b7d 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -829,10 +829,8 @@ dump_type_suffix (tree t, int flags)
 	   anyway; they may in g++, but we'll just pretend otherwise.  */
 	dump_parameters (arg, flags & ~TFF_FUNCTION_DEFAULT_ARGUMENTS);
 
-	if (TREE_CODE (t) == METHOD_TYPE)
-	  pp_cxx_cv_qualifier_seq (cxx_pp, class_of_this_parm (t));
-	else
-	  pp_cxx_cv_qualifier_seq (cxx_pp, t);
+	pp_base (cxx_pp)->padding = pp_before;
+	pp_cxx_cv_qualifiers (cxx_pp, type_memfn_quals (t));
 	dump_ref_qualifier (t, flags);
 	dump_exception_spec (TYPE_RAISES_EXCEPTIONS (t), flags);
 	dump_type_suffix (TREE_TYPE (t), flags);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d143256..f1f8fe2 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -17085,9 +17085,6 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 	 deduces the type of the member as a function type. */
       if (TYPE_PTRMEMFUNC_P (arg))
 	{
-	  tree method_type;
-	  tree fntype;
-
 	  /* Check top-level cv qualifiers */
 	  if (!check_cv_quals_for_unify (UNIFY_ALLOW_NONE, arg, parm))
 	    return unify_cv_qual_mismatch (explain_p, parm, arg);
@@ -17097,17 +17094,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 				   UNIFY_ALLOW_NONE, explain_p);
 
 	  /* Determine the type of the function we are unifying against. */
-	  method_type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (arg));
-	  fntype =
-	    build_function_type (TREE_TYPE (method_type),
-				 TREE_CHAIN (TYPE_ARG_TYPES (method_type)));
-
-	  /* Extract the cv-qualifiers and ref-qualifier of the member
-	     function from the implicit object parameter and place them
-	     on the function type to be restored later. */
-	  fntype = apply_memfn_quals (fntype,
-				      type_memfn_quals (method_type),
-				      type_memfn_rqual (method_type));
+	  tree fntype = static_fn_type (arg);
+
 	  return unify (tparms, targs, TREE_TYPE (parm), fntype, strict, explain_p);
 	}
 

commit 6a69704d6788915ae9773c993d9d6582dc1fd2e4
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Mar 29 21:07:38 2013 -0400

    	* call.c (add_function_candidate): Take the address of 'this' here.
    	(build_over_call): And here.
    	(build_new_method_call_1, build_op_call_1): Not here.
    	(build_user_type_conversion_1): Or here.
    	(add_candidates): Adjust.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 712bd17..b75ca97 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1959,11 +1959,13 @@ add_function_candidate (struct z_candidate **candidates,
 		     object parameter has reference type.  */
 		  bool rv = FUNCTION_RVALUE_QUALIFIED (TREE_TYPE (fn));
 		  parmtype = cp_build_reference_type (parmtype, rv);
-		  arg = build_fold_indirect_ref (arg);
-		  argtype = lvalue_type (arg);
 		}
 	      else
-		parmtype = build_pointer_type (parmtype);
+		{
+		  parmtype = build_pointer_type (parmtype);
+		  arg = build_this (arg);
+		  argtype = lvalue_type (arg);
+		}
 	    }
 
 	  /* Core issue 899: When [copy-]initializing a temporary to be bound
@@ -3460,6 +3462,7 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags,
       int ctorflags = flags;
 
       first_arg = build_int_cst (build_pointer_type (totype), 0);
+      first_arg = build_fold_indirect_ref (first_arg);
 
       /* We should never try to call the abstract or base constructor
 	 from here.  */
@@ -3501,7 +3504,7 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags,
     }
 
   if (conv_fns)
-    first_arg = build_this (expr);
+    first_arg = expr;
 
   for (; conv_fns; conv_fns = TREE_CHAIN (conv_fns))
     {
@@ -4079,7 +4082,7 @@ build_op_call_1 (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
 
   if (fns)
     {
-      first_mem_arg = build_this (obj);
+      first_mem_arg = obj;
 
       add_candidates (BASELINK_FUNCTIONS (fns),
 		      first_mem_arg, *args, NULL_TREE,
@@ -4936,7 +4939,7 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args,
 	 is considered to be a member of the class of the implicit
 	 object argument for the purpose of defining the type of
 	 the implicit object parameter.  */
-      ctype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (first_arg)));
+      ctype = TYPE_MAIN_VARIANT (TREE_TYPE (first_arg));
     }
   else
     {
@@ -4990,7 +4993,7 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args,
 	      for (ix = 1; args->iterate (ix, &arg); ++ix)
 		tempvec->quick_push (arg);
 	      non_static_args = tempvec;
-	      first_arg = build_this ((*args)[0]);
+	      first_arg = (*args)[0];
 	    }
 
 	  fn_first_arg = first_arg;
@@ -6722,16 +6725,18 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
      resolution, and must be of the proper type.  */
   if (DECL_CONSTRUCTOR_P (fn))
     {
+      tree object_arg;
       if (first_arg != NULL_TREE)
 	{
-	  argarray[j++] = first_arg;
+	  object_arg = first_arg;
 	  first_arg = NULL_TREE;
 	}
       else
 	{
-	  argarray[j++] = (*args)[arg_index];
+	  object_arg = (*args)[arg_index];
 	  ++arg_index;
 	}
+      argarray[j++] = build_this (object_arg);
       parm = TREE_CHAIN (parm);
       /* We should never try to call the abstract constructor.  */
       gcc_assert (!DECL_HAS_IN_CHARGE_PARM_P (fn));
@@ -6747,9 +6752,9 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
   else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
     {
       tree parmtype = TREE_VALUE (parm);
-      tree arg = (first_arg != NULL_TREE
-		  ? first_arg
-		  : (*args)[arg_index]);
+      tree arg = build_this (first_arg != NULL_TREE
+			     ? first_arg
+			     : (*args)[arg_index]);
       tree argtype = TREE_TYPE (arg);
       tree converted_arg;
       tree base_binfo;
@@ -7411,7 +7416,6 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
   tree access_binfo;
   tree optype;
   tree first_mem_arg = NULL_TREE;
-  tree instance_ptr;
   tree name;
   bool skip_first_for_error;
   vec<tree, va_gc> *user_args;
@@ -7519,22 +7523,27 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 	return error_mark_node;
     }
 
-  instance_ptr = build_this (instance);
+  /* Consider the object argument to be used even if we end up selecting a
+     static member function.  */
+  instance = mark_type_use (instance);
 
   /* It's OK to call destructors and constructors on cv-qualified objects.
-     Therefore, convert the INSTANCE_PTR to the unqualified type, if
+     Therefore, convert the INSTANCE to the unqualified type, if
      necessary.  */
   if (DECL_DESTRUCTOR_P (fn)
       || DECL_CONSTRUCTOR_P (fn))
     {
-      tree type = build_pointer_type (basetype);
-      if (!same_type_p (type, TREE_TYPE (instance_ptr)))
-	instance_ptr = build_nop (type, instance_ptr);
+      if (!same_type_p (basetype, TREE_TYPE (instance)))
+	{
+	  instance = build_this (instance);
+	  instance = build_nop (build_pointer_type (basetype), instance);
+	  instance = build_fold_indirect_ref (instance);
+	}
     }
   if (DECL_DESTRUCTOR_P (fn))
     name = complete_dtor_identifier;
 
-  first_mem_arg = instance_ptr;
+  first_mem_arg = instance;
 
   /* Get the high-water mark for the CONVERSION_OBSTACK.  */
   p = conversion_obstack_alloc (0);
@@ -7570,11 +7579,10 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 
       if (init)
 	{
-	  tree ob;
-	  if (integer_zerop (instance_ptr))
+	  if (TREE_CODE (instance) == INDIRECT_REF
+	      && integer_zerop (TREE_OPERAND (instance, 0)))
 	    return get_target_expr_sfinae (init, complain);
-	  ob = build_fold_indirect_ref (instance_ptr);
-	  init = build2 (INIT_EXPR, TREE_TYPE (ob), ob, init);
+	  init = build2 (INIT_EXPR, TREE_TYPE (instance), instance, init);
 	  TREE_SIDE_EFFECTS (init) = true;
 	  return init;
 	}
@@ -7599,11 +7607,11 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
       if (complain & tf_error)
 	{
 	  if (!COMPLETE_OR_OPEN_TYPE_P (basetype))
-	    cxx_incomplete_type_error (instance_ptr, basetype);
+	    cxx_incomplete_type_error (instance, basetype);
 	  else if (optype)
 	    error ("no matching function for call to %<%T::operator %T(%A)%#V%>",
 		   basetype, optype, build_tree_list_vec (user_args),
-		   TREE_TYPE (TREE_TYPE (instance_ptr)));
+		   TREE_TYPE (instance));
 	  else
 	    {
 	      char *pretty_name;
@@ -7616,7 +7624,7 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 		arglist = TREE_CHAIN (arglist);
 	      error ("no matching function for call to %<%T::%s(%A)%#V%>",
 		     basetype, pretty_name, arglist,
-		     TREE_TYPE (TREE_TYPE (instance_ptr)));
+		     TREE_TYPE (instance));
 	      if (free_p)
 		free (pretty_name);
 	    }
@@ -7666,7 +7674,7 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 		     fn);
 
 	  if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
-	      && is_dummy_object (instance_ptr))
+	      && is_dummy_object (instance))
 	    {
 	      instance = maybe_resolve_dummy (instance);
 	      if (instance == error_mark_node)
@@ -7675,8 +7683,7 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 		{
 		  /* We captured 'this' in the current lambda now that
 		     we know we really need it.  */
-		  instance_ptr = build_this (instance);
-		  cand->first_arg = instance_ptr;
+		  cand->first_arg = instance;
 		}
 	      else
 		{
@@ -7711,10 +7718,10 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 		 out to be a static member function, `a' is
 		 none-the-less evaluated.  */
 	      if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
-		  && !is_dummy_object (instance_ptr)
-		  && TREE_SIDE_EFFECTS (instance_ptr))
+		  && !is_dummy_object (instance)
+		  && TREE_SIDE_EFFECTS (instance))
 		call = build2 (COMPOUND_EXPR, TREE_TYPE (call),
-			       instance_ptr, call);
+			       instance, call);
 	      else if (call != error_mark_node
 		       && DECL_DESTRUCTOR_P (cand->fn)
 		       && !VOID_TYPE_P (TREE_TYPE (call)))

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