cp-tree.h (cp_cv_quals): New type.
authorMark Mitchell <mark@codesourcery.com>
Sun, 27 Jun 2004 03:03:55 +0000 (03:03 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Sun, 27 Jun 2004 03:03:55 +0000 (03:03 +0000)
* cp-tree.h (cp_cv_quals): New type.
(cp_declarator): Use it instead of "tree" as appropriate.
(grok_method_quals): Adjust prototype.
(grokclassfn): Likewise.
(do_friend): Likewise.
* decl.c (grokfndecl): Use cp_cv_quals, not tree.
(grokdeclarator): Likewise.
* decl2.c (grok_method_quals): Likewise.
(grokclassfn): Likewise.
* friend.c (do_friend): Likewise.
* method.c (implicitly_declare_fn): Adjust call to grokclassfn.
* parser.c (make_call_declarator): Use cp_cv_quals, not tree.
(make_pointer_declarator): Likewise.
(make_reference_declarator): Likewise.
(make_ptrmem_declarator): Likewise.
(cp_parser_ptr_operator): Likewise.
(cp_parser_cv_qualifier_seq_opt): Likewise.
(cp_parser_cv_qualifier_opt): Remove.
(cp_parser_new_declarator_opt): Adjust call to
cp_parser_ptr_operator.
(cp_parser_conversion_declaration_opt): Likewise.
(cp_parser_declarator): Use cp_cv_quals, not tree.
(cp_parser_direct_declarator): Likewise.

From-SVN: r83729

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/friend.c
gcc/cp/method.c
gcc/cp/parser.c

index 6812f8b86a3eed81eec9ea756161c58e1ca6c206..77aeeb08070bd2675d0486a2b6f655d5dad64816 100644 (file)
@@ -1,3 +1,29 @@
+2004-06-26  Mark Mitchell  <mark@codesourcery.com>
+
+       * cp-tree.h (cp_cv_quals): New type.
+       (cp_declarator): Use it instead of "tree" as appropriate.
+       (grok_method_quals): Adjust prototype.
+       (grokclassfn): Likewise.
+       (do_friend): Likewise.
+       * decl.c (grokfndecl): Use cp_cv_quals, not tree.
+       (grokdeclarator): Likewise.
+       * decl2.c (grok_method_quals): Likewise.
+       (grokclassfn): Likewise.
+       * friend.c (do_friend): Likewise.
+       * method.c (implicitly_declare_fn): Adjust call to grokclassfn.
+       * parser.c (make_call_declarator): Use cp_cv_quals, not tree.
+       (make_pointer_declarator): Likewise.
+       (make_reference_declarator): Likewise.
+       (make_ptrmem_declarator): Likewise.
+       (cp_parser_ptr_operator): Likewise.
+       (cp_parser_cv_qualifier_seq_opt): Likewise.
+       (cp_parser_cv_qualifier_opt): Remove.
+       (cp_parser_new_declarator_opt): Adjust call to
+       cp_parser_ptr_operator.
+       (cp_parser_conversion_declaration_opt): Likewise.
+       (cp_parser_declarator): Use cp_cv_quals, not tree.
+       (cp_parser_direct_declarator): Likewise.
+
 2004-06-26  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
 
        * call.c, cp-tree.h, cxx-pretty-print.c, decl.c, decl2.c:
index f2ebb649988af6d8d7ff4a5bcc2e0a5073d44641..54bb0e3bb20b987863969f6635bc35e975d4c2f9 100644 (file)
@@ -3503,6 +3503,11 @@ extern GTY(()) operator_name_info_t operator_name_info
 extern GTY(()) operator_name_info_t assignment_operator_name_info
   [(int) LAST_CPLUS_TREE_CODE];
 
+/* A type-qualifier, or bitmask therefore, using the TYPE_QUAL
+   constants.  */
+
+typedef int cp_cv_quals;
+
 /* A storage class.  */
 
 typedef enum cp_storage_class {
@@ -3628,7 +3633,7 @@ struct cp_declarator {
       /* The parameters to the function.  */
       cp_parameter_declarator *parameters;
       /* The cv-qualifiers for the function.  */
-      tree qualifiers;
+      cp_cv_quals qualifiers;
       /* The exception-specification for the function.  */
       tree exception_specification;
     } function;
@@ -3640,7 +3645,7 @@ struct cp_declarator {
     /* For cdk_pointer, cdk_reference, and cdk_ptrmem.  */
     struct {
       /* The cv-qualifiers for the pointer.  */
-      tree qualifiers;
+      cp_cv_quals qualifiers;
       /* For cdk_ptrmem, the class type containing the member.  */
       tree class_type;
     } pointer;
@@ -3866,10 +3871,10 @@ extern bool have_extern_spec;
 
 /* in decl2.c */
 extern bool check_java_method (tree);
-extern int grok_method_quals (tree, tree, tree);
+extern cp_cv_quals grok_method_quals (tree, tree, cp_cv_quals);
 extern void maybe_retrofit_in_chrg (tree);
 extern void maybe_make_one_only        (tree);
-extern void grokclassfn        (tree, tree, enum overload_flags, tree);
+extern void grokclassfn        (tree, tree, enum overload_flags, cp_cv_quals);
 extern tree grok_array_decl (tree, tree);
 extern tree delete_sanity (tree, tree, bool, int);
 extern tree check_classfn (tree, tree, tree);
@@ -3941,7 +3946,7 @@ extern tree cplus_expand_constant               (tree);
 extern int is_friend                           (tree, tree);
 extern void make_friend_class                  (tree, tree, bool);
 extern void add_friend                          (tree, tree, bool);
-extern tree do_friend                          (tree, tree, tree, tree, enum overload_flags, tree, int);
+extern tree do_friend                          (tree, tree, tree, tree, enum overload_flags, cp_cv_quals, int);
 
 /* in init.c */
 extern tree expand_member_init                 (tree);
index 9d2aedb8123ba0bd1e1547dd6a8a56d1c6753088..838f22bd55af2f423368d792f7cfe843878296d0 100644 (file)
@@ -62,7 +62,7 @@ static int unary_op_p (enum tree_code);
 static void push_local_name (tree);
 static tree grok_reference_init (tree, tree, tree, tree *);
 static tree grokfndecl (tree, tree, tree, tree, tree, int,
-                       enum overload_flags, tree,
+                       enum overload_flags, cp_cv_quals,
                        tree, int, int, int, int, int, int, tree);
 static tree grokvardecl (tree, tree, cp_decl_specifier_seq *, int, int, tree);
 static void record_unknown_type (tree, const char *);
@@ -5424,7 +5424,7 @@ grokfndecl (tree ctype,
             tree orig_declarator,
             int virtualp,
             enum overload_flags flags,
-            tree quals, 
+           cp_cv_quals quals,
             tree raises,
             int check, 
             int friendp, 
@@ -5544,11 +5544,11 @@ grokfndecl (tree ctype,
     DECL_INLINE (decl) = 1;
 
   DECL_EXTERNAL (decl) = 1;
-  if (quals != NULL_TREE && TREE_CODE (type) == FUNCTION_TYPE)
+  if (quals && TREE_CODE (type) == FUNCTION_TYPE)
     {
-      error ("%smember function `%D' cannot have `%T' method qualifier",
-               (ctype ? "static " : "non-"), decl, TREE_VALUE (quals));
-      quals = NULL_TREE;
+      error ("%smember function `%D' cannot have cv-qualifier",
+            (ctype ? "static " : "non-"), decl);
+      quals = TYPE_UNQUALIFIED;
     }
 
   if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)))
@@ -6287,7 +6287,7 @@ grokdeclarator (const cp_declarator *declarator,
   tree dname = NULL_TREE;
   tree ctor_return_type = NULL_TREE;
   enum overload_flags flags = NO_SPECIAL;
-  tree quals = NULL_TREE;
+  cp_cv_quals quals = TYPE_UNQUALIFIED;
   tree raises = NULL_TREE;
   int template_count = 0;
   tree returned_attrs = NULL_TREE;
@@ -6546,7 +6546,7 @@ grokdeclarator (const cp_declarator *declarator,
        } 
       else if (declspecs->specs[(int)ds] > 1)
        {
-         static const char *decl_spec_names[] = {
+         static const char *const decl_spec_names[] = {
            "signed",
            "unsigned",
            "short",
@@ -7049,9 +7049,8 @@ grokdeclarator (const cp_declarator *declarator,
                      error ("destructor cannot be static member function");
                    if (quals)
                      {
-                       error ("destructors may not be `%E'",
-                                 TREE_VALUE (quals));
-                       quals = NULL_TREE;
+                       error ("destructors may not be cv-qualified");
+                       quals = TYPE_UNQUALIFIED;
                      }
                    if (decl_context == FIELD)
                      {
@@ -7078,9 +7077,8 @@ grokdeclarator (const cp_declarator *declarator,
                      }
                    if (quals)
                      {
-                       error ("constructors may not be `%E'",
-                               TREE_VALUE (quals));
-                       quals = NULL_TREE;
+                       error ("constructors may not be cv-qualified");
+                       quals = TYPE_UNQUALIFIED;
                      }
                    if (decl_context == FIELD)
                      {
@@ -7163,7 +7161,7 @@ grokdeclarator (const cp_declarator *declarator,
              grok_method_quals (declarator->u.pointer.class_type, 
                                 dummy, quals);
              type = TREE_TYPE (dummy);
-             quals = NULL_TREE;
+             quals = TYPE_UNQUALIFIED;
            }
 
          if (declarator->kind == cdk_reference)
@@ -7184,45 +7182,9 @@ grokdeclarator (const cp_declarator *declarator,
 
          if (declarator->u.pointer.qualifiers)
            {
-             tree typemodlist;
-             int erred = 0;
-             int constp = 0;
-             int volatilep = 0;
-             int restrictp = 0;
-             
-             for (typemodlist = declarator->u.pointer.qualifiers; typemodlist;
-                  typemodlist = TREE_CHAIN (typemodlist))
-               {
-                 tree qualifier = TREE_VALUE (typemodlist);
-
-                 if (qualifier == ridpointers[(int) RID_CONST])
-                   {
-                     constp++;
-                     type_quals |= TYPE_QUAL_CONST;
-                   }
-                 else if (qualifier == ridpointers[(int) RID_VOLATILE])
-                   {
-                     volatilep++;
-                     type_quals |= TYPE_QUAL_VOLATILE;
-                   }
-                 else if (qualifier == ridpointers[(int) RID_RESTRICT])
-                   {
-                     restrictp++;
-                     type_quals |= TYPE_QUAL_RESTRICT;
-                   }
-                 else if (!erred)
-                   {
-                     erred = 1;
-                     error ("invalid type modifier within pointer declarator");
-                   }
-               }
-             if (constp > 1)
-               pedwarn ("duplicate `const'");
-             if (volatilep > 1)
-               pedwarn ("duplicate `volatile'");
-             if (restrictp > 1)
-               pedwarn ("duplicate `restrict'");
-             type = cp_build_qualified_type (type, type_quals);
+             type 
+               = cp_build_qualified_type (type, 
+                                          declarator->u.pointer.qualifiers);
              type_quals = cp_type_quals (type);
            }
          ctype = NULL_TREE;
@@ -7488,7 +7450,7 @@ grokdeclarator (const cp_declarator *declarator,
          || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
        C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
 
-      bad_specifiers (decl, "type", virtualp, quals != NULL_TREE,
+      bad_specifiers (decl, "type", virtualp, quals != TYPE_UNQUALIFIED, 
                      inlinep, friendp, raises != NULL_TREE);
 
       return decl;
@@ -7654,7 +7616,7 @@ grokdeclarator (const cp_declarator *declarator,
       {
        decl = cp_build_parm_decl (unqualified_id, type);
 
-       bad_specifiers (decl, "parameter", virtualp, quals != NULL_TREE,
+       bad_specifiers (decl, "parameter", virtualp, quals != TYPE_UNQUALIFIED,
                        inlinep, friendp, raises != NULL_TREE);
       }
     else if (decl_context == FIELD)
@@ -7908,7 +7870,7 @@ grokdeclarator (const cp_declarator *declarator,
                  }
              }
 
-           bad_specifiers (decl, "field", virtualp, quals != NULL_TREE,
+           bad_specifiers (decl, "field", virtualp, quals != TYPE_UNQUALIFIED,
                            inlinep, friendp, raises != NULL_TREE);
          }
       }
@@ -8009,7 +7971,7 @@ grokdeclarator (const cp_declarator *declarator,
                            initialized,
                            (type_quals & TYPE_QUAL_CONST) != 0,
                            ctype ? ctype : in_namespace);
-       bad_specifiers (decl, "variable", virtualp, quals != NULL_TREE,
+       bad_specifiers (decl, "variable", virtualp, quals != TYPE_UNQUALIFIED,
                        inlinep, friendp, raises != NULL_TREE);
 
        if (ctype)
index 142bd4b7f871bf0fb4b23c6895eae404ac25fa90..2214e8d3656a7c6a5d6d127f7e63dfdf9423e3d8 100644 (file)
@@ -118,31 +118,15 @@ tree static_dtors;
    TYPE_UNQUALIFIED will be an extension.  */
 
 int
-grok_method_quals (tree ctype, tree function, tree quals)
+grok_method_quals (tree ctype, tree function, cp_cv_quals quals)
 {
   tree fntype = TREE_TYPE (function);
   tree raises = TYPE_RAISES_EXCEPTIONS (fntype);
   int type_quals = TYPE_UNQUALIFIED;
-  int dup_quals = TYPE_UNQUALIFIED;
   int this_quals = TYPE_UNQUALIFIED;
 
-  while (quals)
-    {
-      int tq = cp_type_qual_from_rid (TREE_VALUE (quals));
-      
-      if ((type_quals | this_quals) & tq)
-       dup_quals |= tq;
-      else if (tq & TYPE_QUAL_RESTRICT)
-        this_quals |= tq;
-      else
-       type_quals |= tq;
-      quals = TREE_CHAIN (quals);
-    } 
-
-  if (dup_quals != TYPE_UNQUALIFIED)
-    error ("duplicate type qualifiers in %s declaration",
-             TREE_CODE (function) == FUNCTION_DECL 
-             ? "member function" : "type");
+  type_quals = quals & ~TYPE_QUAL_RESTRICT;
+  this_quals = quals & TYPE_QUAL_RESTRICT;
 
   ctype = cp_build_qualified_type (ctype, type_quals);
   fntype = build_method_type_directly (ctype, TREE_TYPE (fntype),
@@ -281,10 +265,11 @@ maybe_retrofit_in_chrg (tree fn)
    QUALS are the qualifiers for the this pointer.  */
 
 void
-grokclassfn (tree ctype, tree function, enum overload_flags flags, tree quals)
+grokclassfn (tree ctype, tree function, enum overload_flags flags, 
+            cp_cv_quals quals)
 {
   tree fn_name = DECL_NAME (function);
-  int this_quals = TYPE_UNQUALIFIED;
+  cp_cv_quals this_quals = TYPE_UNQUALIFIED;
 
   /* Even within an `extern "C"' block, members get C++ linkage.  See
      [dcl.link] for details.  */
index f815b99f0b92b89f17d38dd73a4c5e72c080aee8..faf558c42451079a8591c10e35f44c52676ff794 100644 (file)
@@ -325,7 +325,8 @@ make_friend_class (tree type, tree friend_type, bool complain)
 
 tree
 do_friend (tree ctype, tree declarator, tree decl,
-          tree attrlist, enum overload_flags flags, tree quals,
+          tree attrlist, enum overload_flags flags, 
+          cp_cv_quals quals,
           int funcdef_flag)
 {
   /* Every decl that gets here is a friend of something.  */
index cc06725c3c3b40bdd68f473ac098f8186c6099b8..adda8da26bcaaa0044a609c1c8b9a1b44fe8bd87 100644 (file)
@@ -1020,7 +1020,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
     }
 
   grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL,
-              /*quals=*/NULL_TREE);
+              TYPE_UNQUALIFIED);
   grok_special_member_properties (fn);
   cp_finish_decl (fn, /*init=*/NULL_TREE, /*asmspec_tree=*/NULL_TREE,
                  /*flags=*/LOOKUP_ONLYCONVERTING);
index e6b1f9208155948b268c7d3f23c718617f3a2e31..1b989dbe283626464c71233511748de345b3fa17 100644 (file)
@@ -1019,17 +1019,17 @@ clear_decl_specs (cp_decl_specifier_seq *decl_specs)
 static cp_declarator *make_id_declarator 
   (tree);
 static cp_declarator *make_call_declarator     
-  (cp_declarator *, cp_parameter_declarator *, tree, tree);
+  (cp_declarator *, cp_parameter_declarator *, cp_cv_quals, tree);
 static cp_declarator *make_array_declarator    
   (cp_declarator *, tree);
 static cp_declarator *make_pointer_declarator  
-  (tree, cp_declarator *);
+  (cp_cv_quals, cp_declarator *);
 static cp_declarator *make_reference_declarator        
-  (tree, cp_declarator *);
+  (cp_cv_quals, cp_declarator *);
 static cp_parameter_declarator *make_parameter_declarator 
   (cp_decl_specifier_seq *, cp_declarator *, tree);
 static cp_declarator *make_ptrmem_declarator   
-  (tree, tree, cp_declarator *);
+  (cp_cv_quals, tree, cp_declarator *);
 
 cp_declarator *cp_error_declarator;
 
@@ -1080,7 +1080,7 @@ make_id_declarator (tree id)
    type, represented as identifiers.  */
 
 cp_declarator *
-make_pointer_declarator (tree cv_qualifiers, cp_declarator *target)
+make_pointer_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target)
 {
   cp_declarator *declarator;
 
@@ -1095,7 +1095,7 @@ make_pointer_declarator (tree cv_qualifiers, cp_declarator *target)
 /* Like make_pointer_declarator -- but for references.  */
 
 cp_declarator *
-make_reference_declarator (tree cv_qualifiers, cp_declarator *target)
+make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target)
 {
   cp_declarator *declarator;
 
@@ -1111,7 +1111,7 @@ make_reference_declarator (tree cv_qualifiers, cp_declarator *target)
    member of CLASS_TYPE.  */
 
 cp_declarator *
-make_ptrmem_declarator (tree cv_qualifiers, tree class_type,
+make_ptrmem_declarator (cp_cv_quals cv_qualifiers, tree class_type,
                        cp_declarator *pointee)
 {
   cp_declarator *declarator;
@@ -1132,7 +1132,7 @@ make_ptrmem_declarator (tree cv_qualifiers, tree class_type,
 cp_declarator *
 make_call_declarator (cp_declarator *target, 
                      cp_parameter_declarator *parms,
-                     tree cv_qualifiers, 
+                     cp_cv_quals cv_qualifiers,
                       tree exception_specification)
 {
   cp_declarator *declarator;
@@ -1693,10 +1693,8 @@ static cp_declarator *cp_parser_declarator
 static cp_declarator *cp_parser_direct_declarator
   (cp_parser *, cp_parser_declarator_kind, int *);
 static enum tree_code cp_parser_ptr_operator
-  (cp_parser *, tree *, tree *);
-static tree cp_parser_cv_qualifier_seq_opt
-  (cp_parser *);
-static tree cp_parser_cv_qualifier_opt
+  (cp_parser *, tree *, cp_cv_quals *);
+static cp_cv_quals cp_parser_cv_qualifier_seq_opt
   (cp_parser *);
 static tree cp_parser_declarator_id
   (cp_parser *);
@@ -4956,12 +4954,12 @@ cp_parser_new_declarator_opt (cp_parser* parser)
 {
   enum tree_code code;
   tree type;
-  tree cv_qualifier_seq;
+  cp_cv_quals cv_quals;
 
   /* We don't know if there's a ptr-operator next, or not.  */
   cp_parser_parse_tentatively (parser);
   /* Look for a ptr-operator.  */
-  code = cp_parser_ptr_operator (parser, &type, &cv_qualifier_seq);
+  code = cp_parser_ptr_operator (parser, &type, &cv_quals);
   /* If that worked, look for more new-declarators.  */
   if (cp_parser_parse_definitely (parser))
     {
@@ -4972,15 +4970,11 @@ cp_parser_new_declarator_opt (cp_parser* parser)
 
       /* Create the representation of the declarator.  */
       if (type)
-       declarator = make_ptrmem_declarator (cv_qualifier_seq,
-                                            type,
-                                            declarator);
+       declarator = make_ptrmem_declarator (cv_quals, type, declarator);
       else if (code == INDIRECT_REF)
-       declarator = make_pointer_declarator (cv_qualifier_seq,
-                                             declarator);
+       declarator = make_pointer_declarator (cv_quals, declarator);
       else
-       declarator = make_reference_declarator (cv_qualifier_seq,
-                                               declarator);
+       declarator = make_reference_declarator (cv_quals, declarator);
 
       return declarator;
     }
@@ -7570,13 +7564,12 @@ cp_parser_conversion_declarator_opt (cp_parser* parser)
 {
   enum tree_code code;
   tree class_type;
-  tree cv_qualifier_seq;
+  cp_cv_quals cv_quals;
 
   /* We don't know if there's a ptr-operator next, or not.  */
   cp_parser_parse_tentatively (parser);
   /* Try the ptr-operator.  */
-  code = cp_parser_ptr_operator (parser, &class_type,
-                                &cv_qualifier_seq);
+  code = cp_parser_ptr_operator (parser, &class_type, &cv_quals);
   /* If it worked, look for more conversion-declarators.  */
   if (cp_parser_parse_definitely (parser))
     {
@@ -7587,15 +7580,12 @@ cp_parser_conversion_declarator_opt (cp_parser* parser)
       
       /* Create the representation of the declarator.  */
       if (class_type)
-       declarator = make_ptrmem_declarator (cv_qualifier_seq,
-                                            class_type,
+       declarator = make_ptrmem_declarator (cv_quals, class_type,
                                             declarator);
       else if (code == INDIRECT_REF)
-       declarator = make_pointer_declarator (cv_qualifier_seq,
-                                             declarator);
+       declarator = make_pointer_declarator (cv_quals, declarator);
       else
-       declarator = make_reference_declarator (cv_qualifier_seq,
-                                               declarator);
+       declarator = make_reference_declarator (cv_quals, declarator);
       
       return declarator;
    }
@@ -10779,7 +10769,7 @@ cp_parser_declarator (cp_parser* parser,
   cp_token *token;
   cp_declarator *declarator;
   enum tree_code code;
-  tree cv_qualifier_seq;
+  cp_cv_quals cv_quals;
   tree class_type;
   tree attributes = NULL_TREE;
 
@@ -10799,7 +10789,7 @@ cp_parser_declarator (cp_parser* parser,
   /* Parse the ptr-operator.  */
   code = cp_parser_ptr_operator (parser,
                                 &class_type,
-                                &cv_qualifier_seq);
+                                &cv_quals);
   /* If that worked, then we have a ptr-operator.  */
   if (cp_parser_parse_definitely (parser))
     {
@@ -10825,15 +10815,13 @@ cp_parser_declarator (cp_parser* parser,
 
       /* Build the representation of the ptr-operator.  */
       if (class_type)
-       declarator = make_ptrmem_declarator (cv_qualifier_seq,
+       declarator = make_ptrmem_declarator (cv_quals,
                                             class_type,
                                             declarator);
       else if (code == INDIRECT_REF)
-       declarator = make_pointer_declarator (cv_qualifier_seq,
-                                             declarator);
+       declarator = make_pointer_declarator (cv_quals, declarator);
       else
-       declarator = make_reference_declarator (cv_qualifier_seq,
-                                               declarator);
+       declarator = make_reference_declarator (cv_quals, declarator);
     }
   /* Everything else is a direct-declarator.  */
   else
@@ -10968,7 +10956,7 @@ cp_parser_direct_declarator (cp_parser* parser,
                 exception-specification.  */
              if (cp_parser_parse_definitely (parser))
                {
-                 tree cv_qualifiers;
+                 cp_cv_quals cv_quals;
                  tree exception_specification;
 
                  if (ctor_dtor_or_conv_p)
@@ -10978,7 +10966,7 @@ cp_parser_direct_declarator (cp_parser* parser,
                  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
 
                  /* Parse the cv-qualifier-seq.  */
-                 cv_qualifiers = cp_parser_cv_qualifier_seq_opt (parser);
+                 cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
                  /* And the exception-specification.  */
                  exception_specification
                    = cp_parser_exception_specification_opt (parser);
@@ -10986,7 +10974,7 @@ cp_parser_direct_declarator (cp_parser* parser,
                  /* Create the function-declarator.  */
                  declarator = make_call_declarator (declarator,
                                                     params,
-                                                    cv_qualifiers,
+                                                    cv_quals,
                                                     exception_specification);
                  /* Any subsequent parameter lists are to do with
                     return type, so are not those of the declared
@@ -11226,17 +11214,17 @@ cp_parser_direct_declarator (cp_parser* parser,
    ptr-operator:
      & cv-qualifier-seq [opt]
 
-   Returns INDIRECT_REF if a pointer, or pointer-to-member, was
-   used.  Returns ADDR_EXPR if a reference was used.  In the
-   case of a pointer-to-member, *TYPE is filled in with the
-   TYPE containing the member.  *CV_QUALIFIER_SEQ is filled in
-   with the cv-qualifier-seq, or NULL_TREE, if there are no
-   cv-qualifiers.  Returns ERROR_MARK if an error occurred.  */
+   Returns INDIRECT_REF if a pointer, or pointer-to-member, was used.
+   Returns ADDR_EXPR if a reference was used.  In the case of a
+   pointer-to-member, *TYPE is filled in with the TYPE containing the
+   member.  *CV_QUALS is filled in with the cv-qualifier-seq, or
+   TYPE_UNQUALIFIED, if there are no cv-qualifiers.  Returns
+   ERROR_MARK if an error occurred.  */
 
 static enum tree_code
 cp_parser_ptr_operator (cp_parser* parser,
                         tree* type,
-                        tree* cv_qualifier_seq)
+                       cp_cv_quals *cv_quals)
 {
   enum tree_code code = ERROR_MARK;
   cp_token *token;
@@ -11244,7 +11232,7 @@ cp_parser_ptr_operator (cp_parser* parser,
   /* Assume that it's not a pointer-to-member.  */
   *type = NULL_TREE;
   /* And that there are no cv-qualifiers.  */
-  *cv_qualifier_seq = NULL_TREE;
+  *cv_quals = TYPE_UNQUALIFIED;
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
@@ -11263,7 +11251,7 @@ cp_parser_ptr_operator (cp_parser* parser,
         enforced during semantic analysis.  */
       if (code == INDIRECT_REF
          || cp_parser_allow_gnu_extensions_p (parser))
-       *cv_qualifier_seq = cp_parser_cv_qualifier_seq_opt (parser);
+       *cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
     }
   else
     {
@@ -11293,7 +11281,7 @@ cp_parser_ptr_operator (cp_parser* parser,
          /* Indicate that the `*' operator was used.  */
          code = INDIRECT_REF;
          /* Look for the optional cv-qualifier-seq.  */
-         *cv_qualifier_seq = cp_parser_cv_qualifier_seq_opt (parser);
+         *cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
        }
       /* If that didn't work we don't have a ptr-operator.  */
       if (!cp_parser_parse_definitely (parser))
@@ -11308,35 +11296,6 @@ cp_parser_ptr_operator (cp_parser* parser,
    cv-qualifier-seq:
      cv-qualifier cv-qualifier-seq [opt]
 
-   Returns a TREE_LIST.  The TREE_VALUE of each node is the
-   representation of a cv-qualifier.  */
-
-static tree
-cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
-{
-  tree cv_qualifiers = NULL_TREE;
-
-  while (true)
-    {
-      tree cv_qualifier;
-
-      /* Look for the next cv-qualifier.  */
-      cv_qualifier = cp_parser_cv_qualifier_opt (parser);
-      /* If we didn't find one, we're done.  */
-      if (!cv_qualifier)
-       break;
-
-      /* Add this cv-qualifier to the list.  */
-      cv_qualifiers
-       = tree_cons (NULL_TREE, cv_qualifier, cv_qualifiers);
-    }
-
-  /* We built up the list in reverse order.  */
-  return nreverse (cv_qualifiers);
-}
-
-/* Parse an (optional) cv-qualifier.
-
    cv-qualifier:
      const
      volatile
@@ -11344,33 +11303,58 @@ cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
    GNU Extension:
 
    cv-qualifier:
-     __restrict__ */
+     __restrict__ 
 
-static tree
-cp_parser_cv_qualifier_opt (cp_parser* parser)
+   Returns a bitmask representing the cv-qualifiers.  */
+
+static cp_cv_quals
+cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
 {
-  cp_token *token;
-  tree cv_qualifier = NULL_TREE;
+  cp_cv_quals cv_quals = TYPE_UNQUALIFIED;
 
-  /* Peek at the next token.  */
-  token = cp_lexer_peek_token (parser->lexer);
-  /* See if it's a cv-qualifier.  */
-  switch (token->keyword)
+  while (true)
     {
-    case RID_CONST:
-    case RID_VOLATILE:
-    case RID_RESTRICT:
-      /* Save the value of the token.  */
-      cv_qualifier = token->value;
-      /* Consume the token.  */
-      cp_lexer_consume_token (parser->lexer);
-      break;
+      cp_token *token;
+      cp_cv_quals cv_qualifier;
+      
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* See if it's a cv-qualifier.  */
+      switch (token->keyword)
+       {
+       case RID_CONST:
+         cv_qualifier = TYPE_QUAL_CONST;
+         break;
+         
+       case RID_VOLATILE:
+         cv_qualifier = TYPE_QUAL_VOLATILE;
+         break;
+         
+       case RID_RESTRICT:
+         cv_qualifier = TYPE_QUAL_RESTRICT;
+         break;
+         
+       default:
+         cv_qualifier = TYPE_UNQUALIFIED;
+         break;
+       }
+      
+      if (!cv_qualifier)
+       break;
 
-    default:
-      break;
+      if (cv_quals & cv_qualifier)
+       {
+         error ("duplicate cv-qualifier");
+         cp_lexer_purge_token (parser->lexer);
+       }
+      else
+       {
+         cp_lexer_consume_token (parser->lexer);
+         cv_quals |= cv_qualifier;
+       }
     }
 
-  return cv_qualifier;
+  return cv_quals;
 }
 
 /* Parse a declarator-id.