This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: C++ PATCH for c++/44193 (incorrect handling of functions, cv-quals and typename)
- From: Jason Merrill <jason at redhat dot com>
- Cc: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Wed, 19 May 2010 16:57:40 -0400
- Subject: Re: C++ PATCH for c++/44193 (incorrect handling of functions, cv-quals and typename)
- References: <4BF40733.8060607@redhat.com>
On 05/19/2010 11:43 AM, Jason Merrill wrote:
In the code for handling TEMPLATE_TYPE_PARM we properly drop cv-quals
when substituting in a function type, but we fail to do the same for
TYPENAME_TYPE. Fixed on the release branches by copying over the code
from the type parm case. For 4.6 I have a more involved patch in the works.
As promised: For 4.6 I'm changing cp_build_qualified_type and
cp_type_quals to ignore the quals on FUNCTION_TYPE in favor of using new
functions type_memfn_quals and apply_memfn_quals, since
function-cv-qualifiers are completely distinct from normal type
qualifiers. This should help to avoid any other similar situations in
the future.
While I was looking at these bits, I also tweaked some related things:
merge-fn-quals.patch -- we were droping function-cv-qualifiers in
merge_types.
dr295.patch -- our handling of applying cv quals to functions was
scattered around the compiler and not consistent. I think we should
just apply the DR 295 resolution in all cases; limiting it to C++0x mode
doesn't make any sense, since it was part of CD1.
cp_type_quals.patch -- Change almost all users of build_qualified_type
and TYPE_QUALS to use cp_build_qualified_type and cp_type_quals
consistently.
Tested x86_64-pc-linux-gnu, applied to trunk.
commit ce4f645b739c9a45d7a41e9ff62901e90e25d522
Author: Jason Merrill <jason@redhat.com>
Date: Wed May 19 13:09:50 2010 -0400
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.
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/g++.dg/template/fntype1.C b/gcc/testsuite/g++.dg/template/fntype1.C
new file mode 100644
index 0000000..d7be273
--- /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);
+}
commit 01673324a00bfc9d34751c6b3295ad49a370797c
Author: Jason Merrill <jason@redhat.com>
Date: Wed May 19 13:21:38 2010 -0400
* typeck.c (merge_types): Preserve memfn quals.
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 44d7ab1..a46b218 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -810,6 +810,7 @@ merge_types (tree t1, tree t2)
tree valtype = merge_types (TREE_TYPE (t1), TREE_TYPE (t2));
tree p1 = TYPE_ARG_TYPES (t1);
tree p2 = TYPE_ARG_TYPES (t2);
+ tree parms;
tree rval, raises;
/* Save space: see if the result is identical to one of the args. */
@@ -821,21 +822,25 @@ merge_types (tree t1, tree t2)
/* Simple way if one arg fails to specify argument types. */
if (p1 == NULL_TREE || TREE_VALUE (p1) == void_type_node)
{
- rval = build_function_type (valtype, p2);
- if ((raises = TYPE_RAISES_EXCEPTIONS (t2)))
- rval = build_exception_variant (rval, raises);
- return cp_build_type_attribute_variant (rval, attributes);
+ parms = p2;
+ raises = TYPE_RAISES_EXCEPTIONS (t2);
}
- raises = TYPE_RAISES_EXCEPTIONS (t1);
- if (p2 == NULL_TREE || TREE_VALUE (p2) == void_type_node)
+ else if (p2 == NULL_TREE || TREE_VALUE (p2) == void_type_node)
{
- rval = build_function_type (valtype, p1);
- if (raises)
- rval = build_exception_variant (rval, raises);
- return cp_build_type_attribute_variant (rval, attributes);
+ parms = p1;
+ raises = TYPE_RAISES_EXCEPTIONS (t1);
+ }
+ else
+ {
+ parms = commonparms (p1, p2);
+ /* In cases where we're merging a real declaration with a
+ built-in declaration, t1 is the real one. */
+ raises = TYPE_RAISES_EXCEPTIONS (t1);
}
- rval = build_function_type (valtype, commonparms (p1, p2));
+ 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));
t1 = build_exception_variant (rval, raises);
break;
}
diff --git a/gcc/testsuite/g++.dg/parse/fn-typedef2.C b/gcc/testsuite/g++.dg/parse/fn-typedef2.C
new file mode 100644
index 0000000..c9c7f06
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/fn-typedef2.C
@@ -0,0 +1,7 @@
+// Test that merge_types preserves fn cv-quals.
+
+typedef void ft() const;
+typedef void V;
+typedef V ft() const;
+
+ft f; // { dg-error "qualified" }
commit 55bb570674dbffa6312da76adde67476cb12d600
Author: Jason Merrill <jason@redhat.com>
Date: Wed May 19 13:15:11 2010 -0400
* decl.c (grokdeclarator): Don't check quals on fn type.
* typeck.c (cp_apply_type_quals_to_decl): Likewise.
* tree.c (cp_build_qualified_type_real): Simplify qualifier checking.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index e57a753..d3cc02b 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8224,21 +8224,6 @@ grokdeclarator (const cp_declarator *declarator,
error ("qualifiers are not allowed on declaration of %<operator %T%>",
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 && cxx_dialect == cxx98)
- {
- tree bad_type = build_qualified_type (type, type_quals);
- pedwarn (input_location, OPT_pedantic,
- "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)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 949734d..e7e43c0 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14099,9 +14099,9 @@ check_cv_quals_for_unify (int strict, tree arg, tree parm)
{
/* Although a CVR qualifier is ignored when being applied to a
substituted template parameter ([8.3.2]/1 for example), that
- does not apply during deduction [14.8.2.4]/1, (even though
- that is not explicitly mentioned, [14.8.2.4]/9 indicates
- this). Except when we're allowing additional CV qualifiers
+ does not allow us to unify "const T" with "int&" because both
+ types are not of the form "cv-list T" [14.8.2.5 temp.deduct.type].
+ It is ok when we're allowing additional CV qualifiers
at the outer level [14.8.2.1]/3,1st bullet. */
if ((TREE_CODE (arg) == REFERENCE_TYPE
|| TREE_CODE (arg) == FUNCTION_TYPE
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 04bfae0..e34a69c 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -865,13 +865,15 @@ cp_build_qualified_type_real (tree type,
}
/* A reference or method type shall not be cv-qualified.
- [dcl.ref], [dcl.fct] */
+ [dcl.ref], [dcl.fct]. This used to be an error, but as of DR 295
+ (in CD1) we always ignore extra cv-quals on functions. */
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);
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ bad_quals |= type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
}
@@ -890,24 +892,16 @@ cp_build_qualified_type_real (tree type,
type_quals &= ~TYPE_QUAL_RESTRICT;
}
- if (bad_quals == TYPE_UNQUALIFIED)
+ if (bad_quals == TYPE_UNQUALIFIED
+ || (complain & tf_ignore_bad_quals))
/*OK*/;
- else if (!(complain & (tf_error | tf_ignore_bad_quals)))
+ else if (!(complain & tf_error))
return error_mark_node;
else
{
- if (complain & tf_ignore_bad_quals)
- /* We're not going to warn about constifying things that can't
- be constified. */
- bad_quals &= ~TYPE_QUAL_CONST;
- if (bad_quals)
- {
- tree bad_type = build_qualified_type (ptr_type_node, bad_quals);
-
- if (!(complain & tf_ignore_bad_quals))
- error ("%qV qualifiers cannot be applied to %qT",
- bad_type, type);
- }
+ tree bad_type = build_qualified_type (ptr_type_node, bad_quals);
+ error ("%qV qualifiers cannot be applied to %qT",
+ bad_type, type);
}
/* Retrieve (or create) the appropriately qualified variant. */
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index a291a9c..44d7ab1 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -7952,23 +7952,8 @@ cp_apply_type_quals_to_decl (int type_quals, tree decl)
if (TREE_CODE (decl) == TYPE_DECL)
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 (input_location, OPT_pedantic,
- "ignoring %qV qualifiers added to function type %qT",
- bad_type, type);
- }
-
- TREE_TYPE (decl) = TYPE_MAIN_VARIANT (type);
- return;
- }
+ gcc_assert (!(TREE_CODE (type) == FUNCTION_TYPE
+ && type_quals != TYPE_UNQUALIFIED));
/* Avoid setting TREE_READONLY incorrectly. */
if (/* If the object has a constructor, the constructor may modify
diff --git a/gcc/testsuite/g++.dg/other/cv_func.C b/gcc/testsuite/g++.dg/other/cv_func.C
index 788c173..941cb8d 100644
--- a/gcc/testsuite/g++.dg/other/cv_func.C
+++ b/gcc/testsuite/g++.dg/other/cv_func.C
@@ -1,5 +1,5 @@
// { dg-do compile }
-// { dg-options "-pedantic -pedantic-errors" }
+
typedef int FIC(int) const;
typedef int FI(int);
@@ -7,15 +7,14 @@ FIC f; // { dg-error "qualified" }
struct S {
FIC f; // OK
- const FI g; // { dg-error "qualifier" }
+ const FI g;
int h(int) const;
};
FIC S::*pm = &S::f;
-const FI S::*pm2 = &S::f; // { dg-error "qualifier" }
-// { dg-error "cannot convert" "cannot convert" { target *-*-* } 16 }
-const FIC S::*pm3 = &S::f; // { dg-error "qualifier" }
+const FI S::*pm2 = &S::f; // { dg-error "cannot convert" }
+const FIC S::*pm3 = &S::f;
int S::f(int) const
{
commit 981a51997b6530fe008db3e60cb9c8f92e87a31e
Author: Jason Merrill <jason@redhat.com>
Date: Tue May 18 12:57:34 2010 -0400
* call.c (reference_binding): Use cp_build_qualified_type_real
and cp_type_quals consistently.
(add_function_candidate): Likewise.
(build_conditional_expr): Likewise.
(convert_like_real): Likewise.
(type_passed_as): Likewise.
* class.c (add_method): Likewise.
(same_signature_p): Likewise.
(layout_class_type): Likewise.
* decl.c (cxx_init_decl_processing): Likewise.
(cp_fname_init): Likewise.
(grokdeclarator): Likewise.
* decl2.c (cp_reconstruct_complex_type): Likewise.
* init.c (build_new_1): Likewise.
* method.c (do_build_copy_constructor): Likewise.
(implicitly_declare_fn): Likewise.
* pt.c (tsubst_aggr_type): Likewise.
(tsubst): Likewise.
* rtti.c (init_rtti_processing): Likewise.
(build_headof): Likewise.
(build_dynamic_cast_1): Likewise.
(tinfo_base_init): Likewise.
(emit_support_tinfos): Likewise.
* semantics.c (capture_decltype): Likewise.
* tree.c (cv_unqualified): Likewise.
* typeck.c (composite_pointer_type): Likewise.
(string_conv_p): Likewise.
* mangle.c (write_CV_qualifiers_for_type): Tweak.
* call.c (initialize_reference): Use CP_TYPE_CONST_P.
* decl.c (start_decl): Likewise.
* semantics.c (finish_compound_literal): Likewise.
* typeck.c (check_return_expr): Use CP_TYPE_VOLATILE_P.
(cp_type_readonly): Remove.
* cp-tree.h: Remove declaration.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 97a196b..3cb30a5 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1246,7 +1246,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
type, so that we can later do a const_cast to the desired type. */
if (related_p && c_cast_p
&& !at_least_as_qualified_p (to, tfrom))
- to = build_qualified_type (to, cp_type_quals (tfrom));
+ to = cp_build_qualified_type (to, cp_type_quals (tfrom));
compatible_p = reference_compatible_p (to, tfrom);
/* Directly bind reference when target expression's type is compatible with
@@ -1617,9 +1617,8 @@ add_function_candidate (struct z_candidate **candidates,
parameter, we can just change the parm type. */
if (ctype && is_this)
{
- parmtype
- = build_qualified_type (ctype,
- TYPE_QUALS (TREE_TYPE (parmtype)));
+ parmtype = cp_build_qualified_type
+ (ctype, cp_type_quals (TREE_TYPE (parmtype)));
parmtype = build_pointer_type (parmtype);
}
@@ -3777,11 +3776,11 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
the type of the other. */
if ((conv2 || conv3)
&& CLASS_TYPE_P (arg2_type)
- && TYPE_QUALS (arg2_type) != TYPE_QUALS (arg3_type))
+ && cp_type_quals (arg2_type) != cp_type_quals (arg3_type))
arg2_type = arg3_type =
cp_build_qualified_type (arg2_type,
- TYPE_QUALS (arg2_type)
- | TYPE_QUALS (arg3_type));
+ cp_type_quals (arg2_type)
+ | cp_type_quals (arg3_type));
}
/* [expr.cond]
@@ -4997,7 +4996,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
}
/* Build up the array. */
elttype = cp_build_qualified_type
- (elttype, TYPE_QUALS (elttype) | TYPE_QUAL_CONST);
+ (elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST);
array = build_array_of_n_type (elttype, len);
array = finish_compound_literal (array, new_ctor);
@@ -5378,7 +5377,7 @@ type_passed_as (tree type)
{
type = build_reference_type (type);
/* There are no other pointers to this temporary. */
- type = build_qualified_type (type, TYPE_QUAL_RESTRICT);
+ type = cp_build_qualified_type (type, TYPE_QUAL_RESTRICT);
}
else if (targetm.calls.promote_prototypes (type)
&& INTEGRAL_TYPE_P (type)
@@ -7735,7 +7734,7 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
{
if (complain & tf_error)
{
- if (!(TYPE_QUALS (TREE_TYPE (type)) & TYPE_QUAL_CONST)
+ if (!CP_TYPE_CONST_P (TREE_TYPE (type))
&& !TYPE_REF_IS_RVALUE (type)
&& !real_lvalue_p (expr))
error ("invalid initialization of non-const reference of "
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 88db80f..748e1b3 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1048,8 +1048,8 @@ add_method (tree type, tree method, tree using_decl)
&& ! DECL_STATIC_FUNCTION_P (method)
&& TREE_TYPE (TREE_VALUE (parms1)) != error_mark_node
&& TREE_TYPE (TREE_VALUE (parms2)) != error_mark_node
- && (TYPE_QUALS (TREE_TYPE (TREE_VALUE (parms1)))
- != TYPE_QUALS (TREE_TYPE (TREE_VALUE (parms2)))))
+ && (cp_type_quals (TREE_TYPE (TREE_VALUE (parms1)))
+ != cp_type_quals (TREE_TYPE (TREE_VALUE (parms2)))))
continue;
/* For templates, the return type and template parameters
@@ -1868,8 +1868,8 @@ same_signature_p (const_tree fndecl, const_tree base_fndecl)
tree types, base_types;
types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
base_types = TYPE_ARG_TYPES (TREE_TYPE (base_fndecl));
- if ((TYPE_QUALS (TREE_TYPE (TREE_VALUE (base_types)))
- == TYPE_QUALS (TREE_TYPE (TREE_VALUE (types))))
+ if ((cp_type_quals (TREE_TYPE (TREE_VALUE (base_types)))
+ == cp_type_quals (TREE_TYPE (TREE_VALUE (types))))
&& compparms (TREE_CHAIN (base_types), TREE_CHAIN (types)))
return 1;
}
@@ -5102,7 +5102,7 @@ layout_class_type (tree t, tree *virtuals_p)
TYPE_UNSIGNED (ftype));
TREE_TYPE (field)
= cp_build_qualified_type (TREE_TYPE (field),
- TYPE_QUALS (ftype));
+ cp_type_quals (ftype));
}
}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6a0dd12..3e1b310 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5415,7 +5415,6 @@ 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);
extern void cp_apply_type_quals_to_decl (int, tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index d3cc02b..43a6bc3 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -3482,7 +3482,7 @@ cxx_init_decl_processing (void)
vtbl_type_node
= build_cplus_array_type (vtable_entry_type, NULL_TREE);
layout_type (vtbl_type_node);
- vtbl_type_node = build_qualified_type (vtbl_type_node, TYPE_QUAL_CONST);
+ vtbl_type_node = cp_build_qualified_type (vtbl_type_node, TYPE_QUAL_CONST);
record_builtin_type (RID_MAX, NULL, vtbl_type_node);
vtbl_ptr_type_node = build_pointer_type (vtable_entry_type);
layout_type (vtbl_ptr_type_node);
@@ -3580,7 +3580,7 @@ cp_fname_init (const char* name, tree *type_p)
init = build_string (length + 1, name);
}
- type = build_qualified_type (char_type_node, TYPE_QUAL_CONST);
+ type = cp_build_qualified_type (char_type_node, TYPE_QUAL_CONST);
type = build_cplus_array_type (type, domain);
*type_p = type;
@@ -4320,7 +4320,7 @@ start_decl (const cp_declarator *declarator,
/* This is a const variable with implicit 'static'. Set
DECL_THIS_STATIC so we can tell it from variables that are
!TREE_PUBLIC because of the anonymous namespace. */
- gcc_assert (cp_type_readonly (TREE_TYPE (decl)));
+ gcc_assert (CP_TYPE_CONST_P (TREE_TYPE (decl)));
DECL_THIS_STATIC (decl) = 1;
}
@@ -8078,8 +8078,8 @@ grokdeclarator (const cp_declarator *declarator,
if (long_p && !longlong && TYPE_MAIN_VARIANT (type) == double_type_node)
{
long_p = false;
- type = build_qualified_type (long_double_type_node,
- cp_type_quals (type));
+ type = cp_build_qualified_type (long_double_type_node,
+ cp_type_quals (type));
}
/* Check all other uses of type modifiers. */
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 29971ce..25c1175 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1272,7 +1272,7 @@ cp_reconstruct_complex_type (tree type, tree bottom)
if (TYPE_ATTRIBUTES (type))
outer = cp_build_type_attribute_variant (outer, TYPE_ATTRIBUTES (type));
- return cp_build_qualified_type (outer, TYPE_QUALS (type));
+ return cp_build_qualified_type (outer, cp_type_quals (type));
}
/* Like decl_attributes, but handle C++ complexity. */
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index e45d2b8..1fb5eb0 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2200,7 +2200,7 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
/* But we want to operate on a non-const version to start with,
since we'll be modifying the elements. */
non_const_pointer_type = build_pointer_type
- (cp_build_qualified_type (type, TYPE_QUALS (type) & ~TYPE_QUAL_CONST));
+ (cp_build_qualified_type (type, cp_type_quals (type) & ~TYPE_QUAL_CONST));
data_addr = fold_convert (non_const_pointer_type, data_addr);
/* Any further uses of alloc_node will want this type, too. */
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 5108950..707df8b 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -1975,18 +1975,19 @@ write_CV_qualifiers_for_type (const tree type)
Note that we do not use cp_type_quals below; given "const
int[3]", the "const" is emitted with the "int", not with the
array. */
+ cp_cv_quals quals = TYPE_QUALS (type);
- if (TYPE_QUALS (type) & TYPE_QUAL_RESTRICT)
+ if (quals & TYPE_QUAL_RESTRICT)
{
write_char ('r');
++num_qualifiers;
}
- if (TYPE_QUALS (type) & TYPE_QUAL_VOLATILE)
+ if (quals & TYPE_QUAL_VOLATILE)
{
write_char ('V');
++num_qualifiers;
}
- if (TYPE_QUALS (type) & TYPE_QUAL_CONST)
+ if (quals & TYPE_QUAL_CONST)
{
write_char ('K');
++num_qualifiers;
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 5ed98bc..43b84dd 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -494,7 +494,7 @@ do_build_copy_constructor (tree fndecl)
if (DECL_MUTABLE_P (field))
quals &= ~TYPE_QUAL_CONST;
- quals |= TYPE_QUALS (expr_type);
+ quals |= cp_type_quals (expr_type);
expr_type = cp_build_qualified_type (expr_type, quals);
}
@@ -934,7 +934,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
if (const_p)
{
data.quals = TYPE_QUAL_CONST;
- rhs_parm_type = build_qualified_type (type, TYPE_QUAL_CONST);
+ rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
}
else
rhs_parm_type = type;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index e7e43c0..85bf1fd 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8760,7 +8760,7 @@ tsubst_aggr_type (tree t,
{
r = lookup_template_class (t, argvec, in_decl, context,
entering_scope, complain);
- r = cp_build_qualified_type_real (r, TYPE_QUALS (t), complain);
+ r = cp_build_qualified_type_real (r, cp_type_quals (t), complain);
}
cp_unevaluated_operand = saved_unevaluated_operand;
@@ -10141,7 +10141,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
/*entering_scope=*/0,
complain);
return cp_build_qualified_type_real
- (r, TYPE_QUALS (t), complain);
+ (r, cp_type_quals (t), complain);
}
else
/* TEMPLATE_TEMPLATE_PARM or TEMPLATE_PARM_INDEX. */
@@ -10331,7 +10331,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
TYPE_REF_IS_RVALUE (t) && TYPE_REF_IS_RVALUE (type));
else
r = cp_build_reference_type (type, TYPE_REF_IS_RVALUE (t));
- r = cp_build_qualified_type_real (r, TYPE_QUALS (t), complain);
+ r = cp_build_qualified_type_real (r, cp_type_quals (t), complain);
if (r != error_mark_node)
/* Will this ever be needed for TYPE_..._TO values? */
@@ -10380,7 +10380,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
}
else
return cp_build_qualified_type_real (build_ptrmem_type (r, type),
- TYPE_QUALS (t),
+ cp_type_quals (t),
complain);
}
case FUNCTION_TYPE:
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index 4eb2ba7..9d300d7 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -155,7 +155,7 @@ init_rtti_processing (void)
/*tag_scope=*/ts_current, false);
pop_namespace ();
const_type_info_type_node
- = build_qualified_type (type_info_type, TYPE_QUAL_CONST);
+ = cp_build_qualified_type (type_info_type, TYPE_QUAL_CONST);
type_info_ptr_type = build_pointer_type (const_type_info_type_node);
unemitted_tinfo_decls = VEC_alloc (tree, gc, 124);
@@ -192,8 +192,8 @@ build_headof (tree exp)
tf_warning_or_error),
index);
- type = build_qualified_type (ptr_type_node,
- cp_type_quals (TREE_TYPE (exp)));
+ type = cp_build_qualified_type (ptr_type_node,
+ cp_type_quals (TREE_TYPE (exp)));
return build2 (POINTER_PLUS_EXPR, type, exp,
convert_to_integer (sizetype, offset));
}
@@ -726,7 +726,7 @@ build_dynamic_cast_1 (tree type, tree expr, tsubst_flags_t complain)
/*tag_scope=*/ts_current, false);
tinfo_ptr = build_pointer_type
- (build_qualified_type
+ (cp_build_qualified_type
(tinfo_ptr, TYPE_QUAL_CONST));
name = "__dynamic_cast";
tmp = tree_cons
@@ -871,7 +871,7 @@ tinfo_base_init (tinfo_s *ti, tree target)
/* Generate the NTBS array variable. */
tree name_type = build_cplus_array_type
- (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
+ (cp_build_qualified_type (char_type_node, TYPE_QUAL_CONST),
NULL_TREE);
/* Determine the name of the variable -- and remember with which
@@ -1495,8 +1495,8 @@ emit_support_tinfos (void)
types[0] = bltn;
types[1] = build_pointer_type (bltn);
- types[2] = build_pointer_type (build_qualified_type (bltn,
- TYPE_QUAL_CONST));
+ types[2] = build_pointer_type (cp_build_qualified_type (bltn,
+ TYPE_QUAL_CONST));
for (i = 0; i < 3; ++i)
{
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 47f3897..173ef96 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2212,7 +2212,7 @@ finish_compound_literal (tree type, tree compound_literal)
if (TREE_CODE (type) == ARRAY_TYPE)
cp_complete_array_type (&type, compound_literal, false);
compound_literal = digest_init (type, compound_literal);
- if ((!at_function_scope_p () || cp_type_readonly (type))
+ if ((!at_function_scope_p () || CP_TYPE_CONST_P (type))
&& initializer_constant_valid_p (compound_literal, type))
{
tree decl = create_temporary_var (type);
@@ -5629,7 +5629,7 @@ capture_decltype (tree decl)
if (TREE_CODE (type) != REFERENCE_TYPE)
{
if (!LAMBDA_EXPR_MUTABLE_P (lam))
- type = cp_build_qualified_type (type, (TYPE_QUALS (type)
+ type = cp_build_qualified_type (type, (cp_type_quals (type)
|TYPE_QUAL_CONST));
type = build_reference_type (type);
}
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index e34a69c..d3bba4c 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -940,7 +940,7 @@ cv_unqualified (tree type)
if (type == error_mark_node)
return type;
- quals = TYPE_QUALS (type);
+ quals = cp_type_quals (type);
quals &= ~(TYPE_QUAL_CONST|TYPE_QUAL_VOLATILE);
return cp_build_qualified_type (type, quals);
}
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index a46b218..54ccbfe 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -633,10 +633,10 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
if (DERIVED_FROM_P (class1, class2))
t2 = (build_pointer_type
- (cp_build_qualified_type (class1, TYPE_QUALS (class2))));
+ (cp_build_qualified_type (class1, cp_type_quals (class2))));
else if (DERIVED_FROM_P (class2, class1))
t1 = (build_pointer_type
- (cp_build_qualified_type (class2, TYPE_QUALS (class1))));
+ (cp_build_qualified_type (class2, cp_type_quals (class1))));
else
{
if (complain & tf_error)
@@ -1250,7 +1250,10 @@ structural_comptypes (tree t1, tree t2, int strict)
/* Qualifiers must match. For array types, we will check when we
recur on the array element types. */
if (TREE_CODE (t1) != ARRAY_TYPE
- && TYPE_QUALS (t1) != TYPE_QUALS (t2))
+ && cp_type_quals (t1) != cp_type_quals (t2))
+ return false;
+ if (TREE_CODE (t1) == FUNCTION_TYPE
+ && type_memfn_quals (t1) != type_memfn_quals (t2))
return false;
if (TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2))
return false;
@@ -2032,7 +2035,7 @@ string_conv_p (const_tree totype, const_tree exp, int warn)
else
{
/* Is this a string constant which has decayed to 'const char *'? */
- t = build_pointer_type (build_qualified_type (t, TYPE_QUAL_CONST));
+ t = build_pointer_type (cp_build_qualified_type (t, TYPE_QUAL_CONST));
if (!same_type_p (TREE_TYPE (exp), t))
return 0;
STRIP_NOPS (exp);
@@ -7642,7 +7645,7 @@ check_return_expr (tree retval, bool *no_warning)
if ((cxx_dialect != cxx98)
&& named_return_value_okay_p
/* The variable must not have the `volatile' qualifier. */
- && !(cp_type_quals (TREE_TYPE (retval)) & TYPE_QUAL_VOLATILE)
+ && !CP_TYPE_VOLATILE_P (TREE_TYPE (retval))
/* The return type must be a class type. */
&& CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
flags = flags | LOOKUP_PREFER_RVALUE;
@@ -7902,17 +7905,6 @@ apply_memfn_quals (tree type, cp_cv_quals memfn_quals)
return build_qualified_type (type, memfn_quals);
}
-/* Returns nonzero if the TYPE is const from a C++ perspective: look inside
- arrays. */
-
-bool
-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. */
- return (cp_type_quals (type) & TYPE_QUAL_CONST) != 0;
-}
-
/* Returns nonzero if TYPE is const or volatile. */
bool