This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: C++ PATCH for c++/44193 (incorrect handling of functions, cv-quals and typename)


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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]