From 9804209d324be049840389053e370d5a1ce51550 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 21 Feb 2005 23:12:27 +0000 Subject: [PATCH] re PR c++/19076 (Pointer to member function not matched to pointer to member template) 2005-02-21 Douglas Gregor PR c++/19076 PR c++/6628 * cp-tree.h (cp_apply_type_quals_to_decl): Declared. * decl.c (grokdeclarator): Pedwarn about qualifying a function type. Add qualifiers when declaring a typedef of a function type. Member function pointers pick up the qualifiers of the typedef used to declare them. Don't complain about creating cv-qualified function types. Complain about qualified function typedefs that are used to declare non-static member functions or free functions. Use cp_apply_type_quals_to_decl. (start_preparsed_function): Use cp_apply_type_quals_to_decl. (grokclassfn): Use cp_apply_type_quals_to_decl. * error.c (dump_type_suffix): Print qualifiers for function types. * pt.c (tsubst_decl): Use cp_apply_type_quals_to_decl. (tsubst): When substituting a function type into a member pointer type, pass along the qualifiers. (unify): Unify member pointers to member function pointers. * tree.c (cp_build_qualified_type_real): Function types may be qualified. This includes restrict qualifiers. * typeck.c (cp_apply_type_quals_to_decl): New function to replace use of c_apply_type_quals_to_decl. Drops qualifiers that are being added to function types. From-SVN: r95356 --- gcc/cp/ChangeLog | 28 +++++++++++++++++++++++ gcc/cp/cp-tree.h | 1 + gcc/cp/decl.c | 55 ++++++++++++++++++++++++++++++++++++++------ gcc/cp/decl2.c | 2 +- gcc/cp/error.c | 2 ++ gcc/cp/pt.c | 59 +++++++++++++++++++++++++++++++++++------------- gcc/cp/tree.c | 6 ++--- gcc/cp/typeck.c | 29 ++++++++++++++++++++++++ 8 files changed, 155 insertions(+), 27 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e190787041b..ae75f8fc23f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,31 @@ +2005-02-21 Douglas Gregor + + PR c++/19076 + PR c++/6628 + * cp-tree.h (cp_apply_type_quals_to_decl): Declared. + * decl.c (grokdeclarator): Pedwarn about qualifying a function + type. + Add qualifiers when declaring a typedef of a function type. + Member function pointers pick up the qualifiers of the typedef + used to declare them. + Don't complain about creating cv-qualified function types. + Complain about qualified function typedefs that are used to + declare non-static member functions or free functions. + Use cp_apply_type_quals_to_decl. + (start_preparsed_function): Use cp_apply_type_quals_to_decl. + (grokclassfn): Use cp_apply_type_quals_to_decl. + * error.c (dump_type_suffix): Print qualifiers for function + types. + * pt.c (tsubst_decl): Use cp_apply_type_quals_to_decl. + (tsubst): When substituting a function type into a member + pointer type, pass along the qualifiers. + (unify): Unify member pointers to member function pointers. + * tree.c (cp_build_qualified_type_real): Function types may be + qualified. This includes restrict qualifiers. + * typeck.c (cp_apply_type_quals_to_decl): New function to replace + use of c_apply_type_quals_to_decl. Drops qualifiers that are being + added to function types. + 2005-02-20 Zack Weinberg PR 18785 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bd5d0eca14d..d99ae7f74c1 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4310,6 +4310,7 @@ extern tree build_ptrmemfunc (tree, tree, int, bool); extern int cp_type_quals (tree); extern bool cp_has_mutable_p (tree); extern bool at_least_as_qualified_p (tree, tree); +extern void cp_apply_type_quals_to_decl (int, tree); extern tree build_ptrmemfunc1 (tree, tree, tree); extern void expand_ptrmemfunc_cst (tree, tree *, tree *); extern tree pfn_from_ptrmemfunc (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 2f6b98f4255..1613488acb7 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6939,6 +6939,20 @@ grokdeclarator (const cp_declarator *declarator, error ("qualifiers are not allowed on declaration of %", ctor_return_type); + if (TREE_CODE (type) == FUNCTION_TYPE + && type_quals != TYPE_UNQUALIFIED) + { + /* This was an error in C++98 (cv-qualifiers cannot be added to + a function type), but DR 295 makes the code well-formed by + dropping the extra qualifiers. */ + if (pedantic) + { + tree bad_type = build_qualified_type (type, type_quals); + pedwarn ("ignoring %qV qualifiers added to function type %qT", + bad_type, type); + } + type_quals = TYPE_UNQUALIFIED; + } type_quals |= cp_type_quals (type); type = cp_build_qualified_type_real (type, type_quals, ((typedef_decl && !DECL_ARTIFICIAL (typedef_decl) @@ -7300,6 +7314,7 @@ grokdeclarator (const cp_declarator *declarator, } type = build_function_type (type, arg_types); + type = cp_build_qualified_type (type, quals); } break; @@ -7332,7 +7347,15 @@ grokdeclarator (const cp_declarator *declarator, && (TREE_CODE (type) == FUNCTION_TYPE || (quals && TREE_CODE (type) == METHOD_TYPE))) { - tree dummy = build_decl (TYPE_DECL, NULL_TREE, type); + tree dummy; + + /* If the type is a FUNCTION_TYPE, pick up the + qualifiers from that function type. No other + qualifiers may be supplied. */ + if (TREE_CODE (type) == FUNCTION_TYPE) + quals = cp_type_quals (type); + + dummy = build_decl (TYPE_DECL, NULL_TREE, type); grok_method_quals (declarator->u.pointer.class_type, dummy, quals); type = TREE_TYPE (dummy); @@ -7629,11 +7652,12 @@ grokdeclarator (const cp_declarator *declarator, { if (ctype == NULL_TREE) { - if (TREE_CODE (type) != METHOD_TYPE) - error ("%Jinvalid type qualifier for non-member function type", - decl); - else + if (TREE_CODE (type) == METHOD_TYPE) ctype = TYPE_METHOD_BASETYPE (type); + /* Any qualifiers on a function type typedef have + already been dealt with. */ + else if (TREE_CODE (type) == FUNCTION_TYPE) + quals = TYPE_UNQUALIFIED; } if (ctype != NULL_TREE) grok_method_quals (ctype, decl, quals); @@ -7676,6 +7700,23 @@ grokdeclarator (const cp_declarator *declarator, } parms = nreverse (decls); + + 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 (cp_type_quals (type) != TYPE_UNQUALIFIED + && (current_class_type == NULL_TREE || staticp) ) + { + error ("qualified function types cannot be used to declare %s functions", + (staticp? "static member" : "free")); + type = TYPE_MAIN_VARIANT (type); + } + + /* The qualifiers on the function type become the qualifiers on + the non-static member function. */ + quals |= cp_type_quals (type); + } } /* If this is a type name (such as, in a cast or sizeof), @@ -8211,7 +8252,7 @@ grokdeclarator (const cp_declarator *declarator, when processing a template; we'll do this for the instantiated declaration based on the type of DECL. */ if (!processing_template_decl) - c_apply_type_quals_to_decl (type_quals, decl); + cp_apply_type_quals_to_decl (type_quals, decl); return decl; } @@ -9995,7 +10036,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags) DECL_IGNORED_P (resdecl) = 1; DECL_RESULT (decl1) = resdecl; - c_apply_type_quals_to_decl (cp_type_quals (restype), resdecl); + cp_apply_type_quals_to_decl (cp_type_quals (restype), resdecl); } /* Initialize RTL machinery. We cannot do this until diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 113386a880f..8243cb14465 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -299,7 +299,7 @@ grokclassfn (tree ctype, tree function, enum overload_flags flags, this_quals |= TYPE_QUAL_CONST; qual_type = cp_build_qualified_type (type, this_quals); parm = build_artificial_parm (this_identifier, qual_type); - c_apply_type_quals_to_decl (this_quals, parm); + cp_apply_type_quals_to_decl (this_quals, parm); TREE_CHAIN (parm) = DECL_ARGUMENTS (function); DECL_ARGUMENTS (function) = parm; } diff --git a/gcc/cp/error.c b/gcc/cp/error.c index ec332f2273b..86ea7aa6eda 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -613,6 +613,8 @@ dump_type_suffix (tree t, int flags) if (TREE_CODE (t) == METHOD_TYPE) pp_cxx_cv_qualifier_seq (cxx_pp, TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t)))); + else + pp_cxx_cv_qualifier_seq(cxx_pp, t); dump_exception_spec (TYPE_RAISES_EXCEPTIONS (t), flags); dump_type_suffix (TREE_TYPE (t), flags); break; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7025deff788..0d83bc1a4d2 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6469,7 +6469,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) type = tsubst (TREE_TYPE (t), args, complain, in_decl); TREE_TYPE (r) = type; - c_apply_type_quals_to_decl (cp_type_quals (type), r); + cp_apply_type_quals_to_decl (cp_type_quals (type), r); if (DECL_INITIAL (r)) { @@ -6499,7 +6499,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (type == error_mark_node) return error_mark_node; TREE_TYPE (r) = type; - c_apply_type_quals_to_decl (cp_type_quals (type), r); + cp_apply_type_quals_to_decl (cp_type_quals (type), r); /* We don't have to set DECL_CONTEXT here; it is set by finish_member_declaration. */ @@ -6599,7 +6599,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) else if (DECL_SELF_REFERENCE_P (t)) SET_DECL_SELF_REFERENCE_P (r); TREE_TYPE (r) = type; - c_apply_type_quals_to_decl (cp_type_quals (type), r); + cp_apply_type_quals_to_decl (cp_type_quals (type), r); DECL_CONTEXT (r) = ctx; /* Clear out the mangled name and RTL for the instantiation. */ SET_DECL_ASSEMBLER_NAME (r, NULL_TREE); @@ -7218,22 +7218,18 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) gcc_assert (TREE_CODE (type) != METHOD_TYPE); if (TREE_CODE (type) == FUNCTION_TYPE) { - /* This is really a method type. The cv qualifiers of the - this pointer should _not_ be determined by the cv - qualifiers of the class type. They should be held - somewhere in the FUNCTION_TYPE, but we don't do that at - the moment. Consider - typedef void (Func) () const; - - template void Foo (Func T1::*); - - */ + /* The type of the implicit object parameter gets its + cv-qualifiers from the FUNCTION_TYPE. */ tree method_type; - - method_type = build_method_type_directly (TYPE_MAIN_VARIANT (r), + tree this_type = cp_build_qualified_type (TYPE_MAIN_VARIANT (r), + cp_type_quals (type)); + tree memptr; + method_type = build_method_type_directly (this_type, TREE_TYPE (type), TYPE_ARG_TYPES (type)); - return build_ptrmemfunc_type (build_pointer_type (method_type)); + memptr = build_ptrmemfunc_type (build_pointer_type (method_type)); + return cp_build_qualified_type_real (memptr, cp_type_quals (t), + complain); } else return cp_build_qualified_type_real (build_ptrmem_type (r, type), @@ -10251,6 +10247,37 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) DEDUCE_EXACT, 0, -1); case OFFSET_TYPE: + /* Unify a pointer to member with a pointer to member function, which + deduces the type of the member as a function type. */ + if (TYPE_PTRMEMFUNC_P (arg)) + { + tree method_type; + tree fntype; + cp_cv_quals cv_quals; + + /* Check top-level cv qualifiers */ + if (!check_cv_quals_for_unify (UNIFY_ALLOW_NONE, arg, parm)) + return 1; + + if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm), + TYPE_PTRMEMFUNC_OBJECT_TYPE (arg), UNIFY_ALLOW_NONE)) + return 1; + + /* 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 of the member function from the + implicit object parameter and place them on the function + type to be restored later. */ + cv_quals = + cp_type_quals(TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (method_type)))); + fntype = build_qualified_type (fntype, cv_quals); + return unify (tparms, targs, TREE_TYPE (parm), fntype, strict); + } + if (TREE_CODE (arg) != OFFSET_TYPE) return 1; if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm), diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8a264d7afa9..321ba4bdbc7 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -499,11 +499,10 @@ cp_build_qualified_type_real (tree type, return build_ptrmemfunc_type (t); } - /* A reference, function or method type shall not be cv qualified. + /* A reference or method type shall not be cv qualified. [dcl.ref], [dct.fct] */ if (type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE) && (TREE_CODE (type) == REFERENCE_TYPE - || TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)) { bad_quals |= type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE); @@ -511,10 +510,11 @@ cp_build_qualified_type_real (tree type, } /* A restrict-qualified type must be a pointer (or reference) - to object or incomplete type. */ + to object or incomplete type, or a function type. */ if ((type_quals & TYPE_QUAL_RESTRICT) && TREE_CODE (type) != TEMPLATE_TYPE_PARM && TREE_CODE (type) != TYPENAME_TYPE + && TREE_CODE (type) != FUNCTION_TYPE && !POINTER_TYPE_P (type)) { bad_quals |= TYPE_QUAL_RESTRICT; diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index e0dc1ebdb49..4a6ded4c4a7 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -6383,6 +6383,35 @@ cp_has_mutable_p (tree type) return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type); } +/* Apply the TYPE_QUALS to the new DECL. */ +void +cp_apply_type_quals_to_decl (int type_quals, tree decl) +{ + tree type = TREE_TYPE (decl); + + if (type == error_mark_node) + return; + + if (TREE_CODE (type) == FUNCTION_TYPE + && type_quals != TYPE_UNQUALIFIED) + { + /* This was an error in C++98 (cv-qualifiers cannot be added to + a function type), but DR 295 makes the code well-formed by + dropping the extra qualifiers. */ + if (pedantic) + { + tree bad_type = build_qualified_type (type, type_quals); + pedwarn ("ignoring %qV qualifiers added to function type %qT", + bad_type, type); + } + + TREE_TYPE (decl) = TYPE_MAIN_VARIANT (type); + return; + } + + c_apply_type_quals_to_decl (type_quals, decl); +} + /* Subroutine of casts_away_constness. Make T1 and T2 point at exemplar types such that casting T1 to T2 is casting away constness if and only if there is no implicit conversion from T1 to T2. */ -- 2.30.2