aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2010-05-19 17:01:50 -0400
committerJason Merrill <jason@gcc.gnu.org>2010-05-19 17:01:50 -0400
commit2872152c39fbc1c91da3fc07e8701fadb6b87f98 (patch)
treea224afc9e9939a2cfe3c63c93d01f4adfa3c5a9d /gcc
parent1961ffb8cd83ccb0f91ce9b3015bb3290f48b04b (diff)
downloadgcc-2872152c39fbc1c91da3fc07e8701fadb6b87f98.zip
gcc-2872152c39fbc1c91da3fc07e8701fadb6b87f98.tar.gz
gcc-2872152c39fbc1c91da3fc07e8701fadb6b87f98.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog20
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/decl.c19
-rw-r--r--gcc/cp/decl2.c6
-rw-r--r--gcc/cp/pt.c22
-rw-r--r--gcc/cp/tree.c8
-rw-r--r--gcc/cp/typeck.c47
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/template/fntype1.C26
9 files changed, 123 insertions, 32 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 0d927c9..255ecd3 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,23 @@
+2010-05-19 Jason Merrill <jason@redhat.com>
+
+ 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 <froydnj@codesourcery.com>
* 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 361a6f2..6a0dd12 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 0636aba..e57a753 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 d811c9e..29971ce 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 7a66d36..949734d 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 bfe65b8..04bfae0 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 dfdd592..a291a9c 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 dc5afe3..7339c62 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2010-05-19 Jason Merrill <jason@redhat.com>
+
+ PR c++/44193
+ * g++.dg/template/fntype1.C: New.
+
2010-05-19 Eric Botcazou <ebotcazou@adacore.com>
* 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 0000000..d7be273a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/fntype1.C
@@ -0,0 +1,26 @@
+bool f(int i) { return i != 5; }
+
+template <class X, class P = bool(X)>
+struct Traits
+{
+ typedef P type;
+};
+
+template <class X, class P = typename Traits<X>::type>
+struct S
+{
+ const P& p_;
+ S( const P& p ) : p_(p) {} // const reference
+};
+
+template <class X>
+S<X> make_s(const typename Traits<X>::type & p) // const reference
+{
+ return S<X>(p); // << HERE
+}
+
+
+int main()
+{
+ make_s<int>(f);
+}