From 2872152c39fbc1c91da3fc07e8701fadb6b87f98 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 19 May 2010 17:01:50 -0400 Subject: [PATCH] re PR c++/44193 (function types, cv-quals and typename) PR c++/44193 * typeck.c (type_memfn_quals): New fn. (apply_memfn_quals): New fn. (cp_type_quals): Return TYPE_UNQUALIFIED for FUNCTION_TYPE. (cp_type_readonly): Use cp_type_quals. * cp-tree.h: Add declarations. * tree.c (cp_build_qualified_type_real): Don't set, but do preserve, quals on FUNCTION_TYPE. (strip_typedefs): Use apply_memfn_quals and type_memfn_quals. * decl.c (build_ptrmem_type): Likewise. (grokdeclarator): Likewise. (static_fn_type): Likewise. * decl2.c (change_return_type): Likewise. (cp_reconstruct_complex_type): Likewise. * pt.c (tsubst_function_type): Likewise. (unify): Likewise. (tsubst): Likewise. Drop special FUNCTION_TYPE substitution code. From-SVN: r159596 --- gcc/cp/ChangeLog | 20 +++++++++++ gcc/cp/cp-tree.h | 2 ++ gcc/cp/decl.c | 19 +++++----- gcc/cp/decl2.c | 6 +++- gcc/cp/pt.c | 22 ++++-------- gcc/cp/tree.c | 8 +++++ gcc/cp/typeck.c | 47 ++++++++++++++++++++++--- gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/g++.dg/template/fntype1.C | 26 ++++++++++++++ 9 files changed, 123 insertions(+), 32 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/fntype1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0d927c9ed262..255ecd3e5c5a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,23 @@ +2010-05-19 Jason Merrill + + PR c++/44193 + * typeck.c (type_memfn_quals): New fn. + (apply_memfn_quals): New fn. + (cp_type_quals): Return TYPE_UNQUALIFIED for FUNCTION_TYPE. + (cp_type_readonly): Use cp_type_quals. + * cp-tree.h: Add declarations. + * tree.c (cp_build_qualified_type_real): Don't set, but do + preserve, quals on FUNCTION_TYPE. + (strip_typedefs): Use apply_memfn_quals and type_memfn_quals. + * decl.c (build_ptrmem_type): Likewise. + (grokdeclarator): Likewise. + (static_fn_type): Likewise. + * decl2.c (change_return_type): Likewise. + (cp_reconstruct_complex_type): Likewise. + * pt.c (tsubst_function_type): Likewise. + (unify): Likewise. + (tsubst): Likewise. Drop special FUNCTION_TYPE substitution code. + 2010-05-18 Nathan Froyd * tree.c (build_min_non_dep_call_vec): Update comment. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 361a6f26b374..6a0dd12aa8fd 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5413,6 +5413,8 @@ extern bool error_type_p (const_tree); extern int ptr_reasonably_similar (const_tree, const_tree); extern tree build_ptrmemfunc (tree, tree, int, bool); extern int cp_type_quals (const_tree); +extern int type_memfn_quals (const_tree); +extern tree apply_memfn_quals (tree, cp_cv_quals); extern bool cp_type_readonly (const_tree); extern bool cp_has_mutable_p (const_tree); extern bool at_least_as_qualified_p (const_tree, const_tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 0636aba01e26..e57a753ea361 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7265,8 +7265,7 @@ build_ptrmem_type (tree class_type, tree member_type) { if (TREE_CODE (member_type) == METHOD_TYPE) { - tree arg_types = TYPE_ARG_TYPES (member_type); - cp_cv_quals quals = cp_type_quals (TREE_TYPE (TREE_VALUE (arg_types))); + cp_cv_quals quals = type_memfn_quals (member_type); member_type = build_memfn_type (member_type, class_type, quals); return build_ptrmemfunc_type (build_pointer_type (member_type)); } @@ -8683,7 +8682,7 @@ grokdeclarator (const cp_declarator *declarator, && (TREE_CODE (type) == FUNCTION_TYPE || (memfn_quals && TREE_CODE (type) == METHOD_TYPE))) { - memfn_quals |= cp_type_quals (type); + memfn_quals |= type_memfn_quals (type); type = build_memfn_type (type, declarator->u.pointer.class_type, memfn_quals); @@ -8691,7 +8690,7 @@ grokdeclarator (const cp_declarator *declarator, } if (TREE_CODE (type) == FUNCTION_TYPE - && cp_type_quals (type) != TYPE_UNQUALIFIED) + && type_memfn_quals (type) != TYPE_UNQUALIFIED) error (declarator->kind == cdk_reference ? G_("cannot declare reference to qualified function type %qT") : G_("cannot declare pointer to qualified function type %qT"), @@ -8994,7 +8993,7 @@ grokdeclarator (const cp_declarator *declarator, function type. */ if (memfn_quals && TREE_CODE (type) == FUNCTION_TYPE) { - type = cp_build_qualified_type (type, memfn_quals); + type = apply_memfn_quals (type, memfn_quals); /* We have now dealt with these qualifiers. */ memfn_quals = TYPE_UNQUALIFIED; @@ -9114,7 +9113,7 @@ grokdeclarator (const cp_declarator *declarator, { /* 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 + if (type_memfn_quals (type) != TYPE_UNQUALIFIED && (current_class_type == NULL_TREE || staticp) ) { error (staticp @@ -9127,7 +9126,7 @@ grokdeclarator (const cp_declarator *declarator, /* The qualifiers on the function type become the qualifiers on the non-static member function. */ - memfn_quals |= cp_type_quals (type); + memfn_quals |= type_memfn_quals (type); type_quals = TYPE_UNQUALIFIED; } } @@ -9195,7 +9194,7 @@ grokdeclarator (const cp_declarator *declarator, type = build_memfn_type (type, ctype, memfn_quals); /* Core issue #547: need to allow this in template type args. */ else if (template_type_arg && TREE_CODE (type) == FUNCTION_TYPE) - type = cp_build_qualified_type (type, memfn_quals); + type = apply_memfn_quals (type, memfn_quals); else error ("invalid qualifiers on non-member function type"); } @@ -12944,7 +12943,6 @@ static_fn_type (tree memfntype) { tree fntype; tree args; - int quals; if (TYPE_PTRMEMFUNC_P (memfntype)) memfntype = TYPE_PTRMEMFUNC_FN_TYPE (memfntype); @@ -12956,8 +12954,7 @@ static_fn_type (tree memfntype) gcc_assert (TREE_CODE (memfntype) == METHOD_TYPE); args = TYPE_ARG_TYPES (memfntype); fntype = build_function_type (TREE_TYPE (memfntype), TREE_CHAIN (args)); - quals = cp_type_quals (TREE_TYPE (TREE_VALUE (args))); - fntype = build_qualified_type (fntype, quals); + fntype = apply_memfn_quals (fntype, type_memfn_quals (memfntype)); fntype = (cp_build_type_attribute_variant (fntype, TYPE_ATTRIBUTES (memfntype))); fntype = (build_exception_variant diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index d811c9e316a5..29971cebbf0c 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -154,7 +154,10 @@ change_return_type (tree new_ret, tree fntype) return fntype; if (TREE_CODE (fntype) == FUNCTION_TYPE) - newtype = build_function_type (new_ret, args); + { + newtype = build_function_type (new_ret, args); + newtype = apply_memfn_quals (newtype, type_memfn_quals (fntype)); + } else newtype = build_method_type_directly (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype))), @@ -1246,6 +1249,7 @@ 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)); } else if (TREE_CODE (type) == METHOD_TYPE) { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7a66d3678269..949734dc2204 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9791,7 +9791,10 @@ tsubst_function_type (tree t, /* Construct a new type node and return it. */ if (TREE_CODE (t) == FUNCTION_TYPE) - fntype = build_function_type (return_type, arg_types); + { + fntype = build_function_type (return_type, arg_types); + fntype = apply_memfn_quals (fntype, type_memfn_quals (t)); + } else { tree r = TREE_TYPE (TREE_VALUE (arg_types)); @@ -9813,7 +9816,6 @@ tsubst_function_type (tree t, fntype = build_method_type_directly (r, return_type, TREE_CHAIN (arg_types)); } - fntype = cp_build_qualified_type_real (fntype, TYPE_QUALS (t), complain); fntype = cp_build_type_attribute_variant (fntype, TYPE_ATTRIBUTES (t)); return fntype; @@ -10111,14 +10113,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) int quals; gcc_assert (TYPE_P (arg)); - /* cv-quals from the template are discarded when - substituting in a function or reference type. */ - if (TREE_CODE (arg) == FUNCTION_TYPE - || TREE_CODE (arg) == METHOD_TYPE - || TREE_CODE (arg) == REFERENCE_TYPE) - quals = cp_type_quals (arg); - else - quals = cp_type_quals (arg) | cp_type_quals (t); + quals = cp_type_quals (arg) | cp_type_quals (t); return cp_build_qualified_type_real (arg, quals, complain | tf_ignore_bad_quals); @@ -10378,7 +10373,7 @@ 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, cp_type_quals (type)); + tree method_type = build_memfn_type (type, r, type_memfn_quals (type)); memptr = build_ptrmemfunc_type (build_pointer_type (method_type)); return cp_build_qualified_type_real (memptr, cp_type_quals (t), complain); @@ -15042,7 +15037,6 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) { 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)) @@ -15061,9 +15055,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) /* 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); + fntype = apply_memfn_quals (fntype, type_memfn_quals (method_type)); return unify (tparms, targs, TREE_TYPE (parm), fntype, strict); } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index bfe65b8418f1..04bfae0b1eee 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -868,12 +868,17 @@ cp_build_qualified_type_real (tree type, [dcl.ref], [dcl.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); type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE); } + /* But preserve any function-cv-quals on a FUNCTION_TYPE. */ + if (TREE_CODE (type) == FUNCTION_TYPE) + type_quals |= type_memfn_quals (type); + /* A restrict-qualified type must be a pointer (or reference) to object or incomplete type. */ if ((type_quals & TYPE_QUAL_RESTRICT) @@ -1038,8 +1043,11 @@ strip_typedefs (tree t) TREE_CHAIN (arg_types)); } else + { result = build_function_type (type, arg_types); + result = apply_memfn_quals (result, type_memfn_quals (t)); + } if (TYPE_RAISES_EXCEPTIONS (t)) result = build_exception_variant (result, diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index dfdd5925a37d..a291a9cec306 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -7851,12 +7851,50 @@ comp_ptr_ttypes_const (tree to, tree from) int cp_type_quals (const_tree type) { + int quals; /* This CONST_CAST is okay because strip_array_types returns its argument unmodified and we assign it to a const_tree. */ - type = strip_array_types (CONST_CAST_TREE(type)); - if (type == error_mark_node) + type = strip_array_types (CONST_CAST_TREE (type)); + if (type == error_mark_node + /* Quals on a FUNCTION_TYPE are memfn quals. */ + || TREE_CODE (type) == FUNCTION_TYPE) return TYPE_UNQUALIFIED; - return TYPE_QUALS (type); + quals = TYPE_QUALS (type); + /* METHOD and REFERENCE_TYPEs should never have quals. */ + gcc_assert ((TREE_CODE (type) != METHOD_TYPE + && TREE_CODE (type) != REFERENCE_TYPE) + || ((quals & (TYPE_QUAL_CONST|TYPE_QUAL_VOLATILE)) + == TYPE_UNQUALIFIED)); + return quals; +} + +/* Returns the function-cv-quals for TYPE, which must be a FUNCTION_TYPE or + METHOD_TYPE. */ + +int +type_memfn_quals (const_tree type) +{ + if (TREE_CODE (type) == FUNCTION_TYPE) + return TYPE_QUALS (type); + else if (TREE_CODE (type) == METHOD_TYPE) + return cp_type_quals (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type)))); + else + gcc_unreachable (); +} + +/* Returns the FUNCTION_TYPE TYPE with its function-cv-quals changed to + MEMFN_QUALS. */ + +tree +apply_memfn_quals (tree type, cp_cv_quals memfn_quals) +{ + /* Could handle METHOD_TYPE here if necessary. */ + gcc_assert (TREE_CODE (type) == FUNCTION_TYPE); + if (TYPE_QUALS (type) == memfn_quals) + return type; + /* This should really have a different TYPE_MAIN_VARIANT, but that gets + complex. */ + return build_qualified_type (type, memfn_quals); } /* Returns nonzero if the TYPE is const from a C++ perspective: look inside @@ -7867,8 +7905,7 @@ cp_type_readonly (const_tree type) { /* This CONST_CAST is okay because strip_array_types returns its argument unmodified and we assign it to a const_tree. */ - type = strip_array_types (CONST_CAST_TREE(type)); - return TYPE_READONLY (type); + return (cp_type_quals (type) & TYPE_QUAL_CONST) != 0; } /* Returns nonzero if TYPE is const or volatile. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index dc5afe30b2ed..7339c6222702 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-05-19 Jason Merrill + + PR c++/44193 + * g++.dg/template/fntype1.C: New. + 2010-05-19 Eric Botcazou * gnat.dg/discr23.ad[sb]: New test. diff --git a/gcc/testsuite/g++.dg/template/fntype1.C b/gcc/testsuite/g++.dg/template/fntype1.C new file mode 100644 index 000000000000..d7be273aa421 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/fntype1.C @@ -0,0 +1,26 @@ +bool f(int i) { return i != 5; } + +template +struct Traits +{ + typedef P type; +}; + +template ::type> +struct S +{ + const P& p_; + S( const P& p ) : p_(p) {} // const reference +}; + +template +S make_s(const typename Traits::type & p) // const reference +{ + return S(p); // << HERE +} + + +int main() +{ + make_s(f); +} -- 2.43.5