From 2eed8e37019cecd79d95b81ecfb6f8605b6361fa Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Mon, 1 Apr 2013 19:04:59 +0000 Subject: [PATCH] Implement N2439 (ref-qualifiers for 'this') 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. Co-Authored-By: Jason Merrill From-SVN: r197315 --- gcc/cp/ChangeLog | 40 ++++++++++++ gcc/cp/call.c | 17 ++++- gcc/cp/class.c | 20 ++++-- gcc/cp/cp-tree.h | 45 +++++++++++-- gcc/cp/decl.c | 88 +++++++++++++++++++------- gcc/cp/decl2.c | 22 +++++-- gcc/cp/error.c | 23 +++++++ gcc/cp/parser.c | 49 +++++++++++++- gcc/cp/pt.c | 19 ++++-- gcc/cp/tree.c | 83 ++++++++++++++++++++++-- gcc/cp/typeck.c | 39 ++++++++++-- gcc/cp/typeck2.c | 19 +++++- gcc/testsuite/g++.dg/cpp0x/ref-qual1.C | 30 +++++++++ gcc/testsuite/g++.dg/cpp0x/ref-qual2.C | 75 ++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp0x/ref-qual3.C | 29 +++++++++ gcc/testsuite/g++.dg/cpp0x/ref-qual4.C | 14 ++++ gcc/testsuite/g++.dg/cpp0x/ref-qual5.C | 13 ++++ gcc/testsuite/g++.dg/cpp0x/ref-qual6.C | 15 +++++ gcc/testsuite/g++.dg/cpp0x/ref-qual7.C | 19 ++++++ gcc/testsuite/g++.dg/cpp0x/ref-qual8.C | 13 ++++ 20 files changed, 612 insertions(+), 60 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-qual1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-qual2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-qual3.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-qual4.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-qual5.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-qual6.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-qual7.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/ref-qual8.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f96c2643059..598c2a52ee9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,43 @@ +2013-04-01 Bronek Kozicki + Jason Merrill + + 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. + 2013-04-01 Paolo Carlini * cp-tree.h (DECL_UNBOUND_CLASS_TEMPLATE_P): Remove. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 5df6b475c83..712bd17af0f 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 cea8a512cd3..54180a27994 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 3119105863b..74ea4e49b83 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 98d30dd99eb..9e280eac9f7 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 e14c38814eb..ef1f1e7d850 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 38da24304e0..6df8987a63f 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 a5cf66d304e..f29e80db7c5 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 7f4212de9a8..d143256b455 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 7fb8698ecfc..ce9568c505e 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" 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 ae9267509b6..763fc0b3b08 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 61ec4b58f64..d9efafb8515 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 00000000000..7fa826c3db4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/ref-qual1.C @@ -0,0 +1,30 @@ +// { dg-require-effective-target c++11 } + +template struct ST; +template struct ST {}; + +struct A +{ + int f() &; + char f() &&; +}; + +template struct B +{ + int f() &; + char f() &&; +}; + +int main() +{ + A a; + a.f(); + A().f(); + ST(); + ST(); + B b; + b.f(); + B().f(); + ST(); + ST().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 00000000000..fa09ab48a15 --- /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 +struct B { + void f() &; + void g() &&; + void h(); +}; + +template +void two() +{ + B a; + + void (B::*p)() & = &B::f; + (a.*p)(); + (B().*p)(); // { dg-error "" } + + p = &B::g; // { dg-error "" } + p = &B::h; // { dg-error "" } + + void (B::*p2)() && = &B::g; + (B().*p2)(); + (a.*p2)(); // { dg-error "" } + p2 = &B::f; // { dg-error "" } + p2 = &B::h; // { dg-error "" } + + void (B::*p3)() = &B::h; + (a.*p3)(); + (B().*p3)(); + p3 = &B::f; // { dg-error "" } + p3 = &B::g; // { dg-error "" } +} + +int main() +{ + one(); + two(); +} 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 00000000000..1b21196321a --- /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 +struct B { + B& operator=(const B&) & = default; +}; + +template +void f() +{ + B b; + b = B(); + B() = b; // { dg-error "" } +} + +int main() +{ + A a; + a = A(); + A() = a; // { dg-error "" } + + f(); +} 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 00000000000..5a0ee162fe5 --- /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 00000000000..e3d26e5a78f --- /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 00000000000..02e3f6e683e --- /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 00000000000..2430665db34 --- /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 00000000000..b4c972b3c3b --- /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" }