OSDN Git Service

cp:
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 22 Feb 2002 11:57:52 +0000 (11:57 +0000)
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 22 Feb 2002 11:57:52 +0000 (11:57 +0000)
PR c++/2645, DR 295
* cp-tree.h (tsubst_flags_t): Add tf_ignore_bad_quals,
tf_keep_type_decl.
(make_typename_type): Use tsubst_flags_t.
* decl.c (make_typename_type): Adjust. Return non-artificial
TYPE_DECLs, if required.
(grokdeclarator): Simplify CVR qualification handling. Allow bad
qualifiers on typedef types.
* decl2.c (handle_class_head): Adjust make_typename_type call.
* parse.y (nested_name_specifier): Likewise.
(typename_sub0): Likewise.
(typename_sub1): Likewise.
* pt.c (convert_template_argument): Adjust make_typename_type
return value.
(tsubst): Adjust cp_build_qualified_type_real calls.
(check_cv_quals_for_unify): Cope with alowing bad qualifications
on template type parms.
(instantiate_decl): Recheck substitutions to give warnings on bad
qualifications.
* tree.c (cp_build_qualified_type_real): Use tf_allow_bad_quals.
testsuite:
* g++.dg/template/qualttp19.C: New test.
* g++.dg/template/qualttp20.C: New test.
* g++.old-deja/g++.jason/report.C: Adjust expected errors
* g++.old-deja/g++.other/qual1.C: Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@49961 138bc75d-0d04-0410-961f-82ee72b054a4

12 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/parse.y
gcc/cp/pt.c
gcc/cp/tree.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/qualttp19.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/qualttp20.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.jason/report.C
gcc/testsuite/g++.old-deja/g++.other/qual1.C

index 69e2332..31fc320 100644 (file)
@@ -1,3 +1,26 @@
+2002-02-22  Nathan Sidwell  <nathan@codesourcery.com>
+
+       PR c++/2645, DR 295
+       * cp-tree.h (tsubst_flags_t): Add tf_ignore_bad_quals,
+       tf_keep_type_decl.
+       (make_typename_type): Use tsubst_flags_t.
+       * decl.c (make_typename_type): Adjust. Return non-artificial
+       TYPE_DECLs, if required.
+       (grokdeclarator): Simplify CVR qualification handling. Allow bad
+       qualifiers on typedef types.
+       * decl2.c (handle_class_head): Adjust make_typename_type call.
+       * parse.y (nested_name_specifier): Likewise.
+       (typename_sub0): Likewise.
+       (typename_sub1): Likewise.
+       * pt.c (convert_template_argument): Adjust make_typename_type
+       return value.
+       (tsubst): Adjust cp_build_qualified_type_real calls.
+       (check_cv_quals_for_unify): Cope with alowing bad qualifications
+       on template type parms.
+       (instantiate_decl): Recheck substitutions to give warnings on bad
+       qualifications.
+       * tree.c (cp_build_qualified_type_real): Use tf_allow_bad_quals.
+
 2002-02-21  Aldy Hernandez  <aldyh@redhat.com>
 
         * cp/decl.c (duplicate_decls): Merge always_inline attribute.
index 169d1a2..ad82612 100644 (file)
@@ -3070,7 +3070,10 @@ typedef enum tsubst_flags_t {
   tf_warning = 1 << 1,       /* give warnings too  */
   tf_no_attributes = 1 << 2, /* ignore attributes on comparisons
                                (instantiate_type use) */
-  tf_ptrmem_ok = 1 << 3      /* pointers to member ok (internal
+  tf_ignore_bad_quals = 1 << 3, /* ignore bad cvr qualifiers */
+  tf_keep_type_decl = 1 << 4,  /* retain typedef type decls
+                                  (make_typename_type use) */
+  tf_ptrmem_ok = 1 << 5      /* pointers to member ok (internal
                                instantiate_type use) */
 } tsubst_flags_t;
 
@@ -3693,7 +3696,7 @@ extern tree namespace_binding                   PARAMS ((tree, tree));
 extern void set_namespace_binding               PARAMS ((tree, tree, tree));
 extern tree lookup_namespace_name              PARAMS ((tree, tree));
 extern tree build_typename_type                 PARAMS ((tree, tree, tree, tree));
-extern tree make_typename_type                 PARAMS ((tree, tree, int));
+extern tree make_typename_type                 PARAMS ((tree, tree, tsubst_flags_t));
 extern tree make_unbound_class_template                PARAMS ((tree, tree, int));
 extern tree lookup_name_nonclass               PARAMS ((tree));
 extern tree lookup_function_nonclass            PARAMS ((tree, tree));
index a91b3da..4d912cd 100644 (file)
@@ -5609,12 +5609,15 @@ build_typename_type (context, name, fullname, base_type)
 
 /* Resolve `typename CONTEXT::NAME'.  Returns an appropriate type,
    unless an error occurs, in which case error_mark_node is returned.
-   If COMPLAIN zero, don't complain about any errors that occur.  */
+   If we locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is
+   set, we return that, rather than the _TYPE it corresponds to, in
+   other cases we look through the type decl.  If TF_ERROR is set,
+   complain about errors, otherwise be quiet.  */
 
 tree
 make_typename_type (context, name, complain)
      tree context, name;
-     int complain;
+     tsubst_flags_t complain;
 {
   tree fullname;
 
@@ -5653,7 +5656,7 @@ make_typename_type (context, name, complain)
     {
       /* We can get here from typename_sub0 in the explicit_template_type
         expansion.  Just fail.  */
-      if (complain)
+      if (complain & tf_error)
        error ("no class template named `%#T' in `%#T'",
                  name, context);
       return error_mark_node;
@@ -5669,7 +5672,7 @@ make_typename_type (context, name, complain)
            tmpl = lookup_field (context, name, 0, 0);
          if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl))
            {
-             if (complain)
+             if (complain & tf_error)
                error ("no class template named `%#T' in `%#T'",
                          name, context);
              return error_mark_node;
@@ -5687,14 +5690,18 @@ make_typename_type (context, name, complain)
 
          if (!IS_AGGR_TYPE (context))
            {
-             if (complain)
+             if (complain & tf_error)
                error ("no type named `%#T' in `%#T'", name, context);
              return error_mark_node;
            }
 
          t = lookup_field (context, name, 0, 1);
          if (t)
-           return TREE_TYPE (t);
+           {
+             if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
+               t = TREE_TYPE (t);
+             return t;
+           }
        }
     }
 
@@ -5702,7 +5709,7 @@ make_typename_type (context, name, complain)
      there now or its never going to be.  */
   if (!uses_template_parms (context))
     {
-      if (complain)
+      if (complain & tf_error)
        error ("no type named `%#T' in `%#T'", name, context);
       return error_mark_node;
     }
@@ -5713,7 +5720,9 @@ make_typename_type (context, name, complain)
 
 /* Resolve `CONTEXT::template NAME'.  Returns an appropriate type,
    unless an error occurs, in which case error_mark_node is returned.
-   If COMPLAIN zero, don't complain about any errors that occur.  */
+   If we locate a TYPE_DECL, we return that, rather than the _TYPE it
+   corresponds to.  If COMPLAIN zero, don't complain about any errors
+   that occur.  */
 
 tree
 make_unbound_class_template (context, name, complain)
@@ -9606,9 +9615,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
   tree spec;
   tree type = NULL_TREE;
   int longlong = 0;
-  int constp;
-  int restrictp;
-  int volatilep;
   int type_quals;
   int virtualp, explicitp, friendp, inlinep, staticp;
   int explicit_int = 0;
@@ -10314,26 +10320,24 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
        type = build_complex_type (type);
     }
 
-  if (sfk == sfk_conversion
-      && (RIDBIT_SETP (RID_CONST, specbits)
-         || RIDBIT_SETP (RID_VOLATILE, specbits)
-         || RIDBIT_SETP (RID_RESTRICT, specbits)))
+  type_quals = TYPE_UNQUALIFIED;
+  if (RIDBIT_SETP (RID_CONST, specbits))
+    type_quals |= TYPE_QUAL_CONST;
+  if (RIDBIT_SETP (RID_VOLATILE, specbits))
+    type_quals |= TYPE_QUAL_VOLATILE;
+  if (RIDBIT_SETP (RID_RESTRICT, specbits))
+    type_quals |= TYPE_QUAL_RESTRICT;
+  if (sfk == sfk_conversion && type_quals != TYPE_UNQUALIFIED)
     error ("qualifiers are not allowed on declaration of `operator %T'",
              ctor_return_type);
 
-  /* Set CONSTP if this declaration is `const', whether by
-     explicit specification or via a typedef.
-     Likewise for VOLATILEP.  */
-
-  constp = !! RIDBIT_SETP (RID_CONST, specbits) + CP_TYPE_CONST_P (type);
-  restrictp =
-    !! RIDBIT_SETP (RID_RESTRICT, specbits) + CP_TYPE_RESTRICT_P (type);
-  volatilep =
-    !! RIDBIT_SETP (RID_VOLATILE, specbits) + CP_TYPE_VOLATILE_P (type);
-  type_quals = ((constp ? TYPE_QUAL_CONST : 0)
-               | (restrictp ? TYPE_QUAL_RESTRICT : 0)
-               | (volatilep ? TYPE_QUAL_VOLATILE : 0));
-  type = cp_build_qualified_type (type, type_quals);
+  type_quals |= cp_type_quals (type);
+  type = cp_build_qualified_type_real
+    (type, type_quals, ((typedef_decl && !DECL_ARTIFICIAL (typedef_decl)
+                        ? tf_ignore_bad_quals : 0) | tf_error | tf_warning));
+  /* We might have ignored or rejected some of the qualifiers.  */
+  type_quals = cp_type_quals (type);
+  
   staticp = 0;
   inlinep = !! RIDBIT_SETP (RID_INLINE, specbits);
   virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits);
@@ -10826,21 +10830,30 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            {
              register tree typemodlist;
              int erred = 0;
-
-             constp = 0;
-             volatilep = 0;
-             restrictp = 0;
+             int constp = 0;
+             int volatilep = 0;
+             int restrictp = 0;
+             
              for (typemodlist = TREE_TYPE (declarator); typemodlist;
                   typemodlist = TREE_CHAIN (typemodlist))
                {
                  tree qualifier = TREE_VALUE (typemodlist);
 
                  if (qualifier == ridpointers[(int) RID_CONST])
-                   constp++;
+                   {
+                     constp++;
+                     type_quals |= TYPE_QUAL_CONST;
+                   }
                  else if (qualifier == ridpointers[(int) RID_VOLATILE])
-                   volatilep++;
+                   {
+                     volatilep++;
+                     type_quals |= TYPE_QUAL_VOLATILE;
+                   }
                  else if (qualifier == ridpointers[(int) RID_RESTRICT])
-                   restrictp++;
+                   {
+                     restrictp++;
+                     type_quals |= TYPE_QUAL_RESTRICT;
+                   }
                  else if (!erred)
                    {
                      erred = 1;
@@ -10853,20 +10866,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                pedwarn ("duplicate `volatile'");
              if (restrictp > 1)
                pedwarn ("duplicate `restrict'");
-
-             type_quals = ((constp ? TYPE_QUAL_CONST : 0)
-                           | (restrictp ? TYPE_QUAL_RESTRICT : 0)
-                           | (volatilep ? TYPE_QUAL_VOLATILE : 0));
-             if (TREE_CODE (declarator) == ADDR_EXPR
-                 && (constp || volatilep))
-               {
-                 if (constp)
-                   pedwarn ("discarding `const' applied to a reference");
-                 if (volatilep)
-                   pedwarn ("discarding `volatile' applied to a reference");
-                 type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
-               }
              type = cp_build_qualified_type (type, type_quals);
+             type_quals = cp_type_quals (type);
            }
          declarator = TREE_OPERAND (declarator, 0);
          ctype = NULL_TREE;
@@ -11110,7 +11111,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       else if (type_quals & TYPE_QUAL_CONST)
        {
          error ("const `%s' cannot be declared `mutable'", name);
-         RIDBIT_RESET (RID_MUTABLE, specbits);
+         RIDBIT_RESET (RID_MUTABLE, specbits);
        }
     }
 
index 0cbb321..ea1d297 100644 (file)
@@ -5219,7 +5219,7 @@ handle_class_head (aggr, scope, id, defn_p, new_type_p)
            {
              /* According to the suggested resolution of core issue
                 180, 'typename' is assumed after a class-key.  */
-             decl = make_typename_type (scope, id, 1);
+             decl = make_typename_type (scope, id, tf_error);
              if (decl != error_mark_node)
                decl = TYPE_MAIN_DECL (decl);
              else
index 54a6823..e6bdc9a 100644 (file)
@@ -3029,14 +3029,14 @@ nested_name_specifier:
                { $$ = $2; }
        | nested_name_specifier TEMPLATE explicit_template_type SCOPE
                 { got_scope = $$ 
-                   = make_typename_type ($1, $3, /*complain=*/1); }
+                   = make_typename_type ($1, $3, tf_error); }
        /* Error handling per Core 125.  */
        | nested_name_specifier IDENTIFIER SCOPE
                 { got_scope = $$ 
-                   = make_typename_type ($1, $2, /*complain=*/1); }
+                   = make_typename_type ($1, $2, tf_error); }
        | nested_name_specifier PTYPENAME SCOPE
                 { got_scope = $$ 
-                   = make_typename_type ($1, $2, /*complain=*/1); }
+                   = make_typename_type ($1, $2, tf_error); }
        ;
 
 /* Why the @#$%^& do type_name and notype_identifier need to be expanded
@@ -3078,7 +3078,7 @@ typename_sub0:
          typename_sub1 identifier %prec EMPTY
                {
                  if (TYPE_P ($1))
-                   $$ = make_typename_type ($1, $2, /*complain=*/1);
+                   $$ = make_typename_type ($1, $2, tf_error);
                  else if (TREE_CODE ($2) == IDENTIFIER_NODE)
                    error ("`%T' is not a class or namespace", $2);
                  else
@@ -3091,9 +3091,9 @@ typename_sub0:
        | typename_sub1 template_type %prec EMPTY
                { $$ = TREE_TYPE ($2); }
        | typename_sub1 explicit_template_type %prec EMPTY
-                { $$ = make_typename_type ($1, $2, /*complain=*/1); }
+                { $$ = make_typename_type ($1, $2, tf_error); }
        | typename_sub1 TEMPLATE explicit_template_type %prec EMPTY
-                { $$ = make_typename_type ($1, $3, /*complain=*/1); }
+                { $$ = make_typename_type ($1, $3, tf_error); }
        ;
 
 typename_sub1:
@@ -3107,7 +3107,7 @@ typename_sub1:
        | typename_sub1 typename_sub2
                {
                  if (TYPE_P ($1))
-                   $$ = make_typename_type ($1, $2, /*complain=*/1);
+                   $$ = make_typename_type ($1, $2, tf_error);
                  else if (TREE_CODE ($2) == IDENTIFIER_NODE)
                    error ("`%T' is not a class or namespace", $2);
                  else
@@ -3119,10 +3119,10 @@ typename_sub1:
                }
        | typename_sub1 explicit_template_type SCOPE
                 { got_scope = $$ 
-                   = make_typename_type ($1, $2, /*complain=*/1); }
+                   = make_typename_type ($1, $2, tf_error); }
        | typename_sub1 TEMPLATE explicit_template_type SCOPE
                 { got_scope = $$ 
-                   = make_typename_type ($1, $3, /*complain=*/1); }
+                   = make_typename_type ($1, $3, tf_error); }
        ;
 
 /* This needs to return a TYPE_DECL for simple names so that we don't
index 4a57dd3..152ac0e 100644 (file)
@@ -3335,8 +3335,6 @@ convert_template_argument (parm, arg, args, complain, i, in_decl)
       arg = make_typename_type (TREE_OPERAND (arg, 0),
                                TREE_OPERAND (arg, 1),
                                complain & tf_error);
-      if (TREE_CODE (arg) == TYPE_DECL)
-       arg = TREE_TYPE (arg);
       is_type = 1;
     }
   if (is_type != requires_type)
@@ -6407,7 +6405,7 @@ tsubst (t, args, complain, in_decl)
                    my_friendly_assert (TYPE_P (arg), 0);
                    return cp_build_qualified_type_real
                      (arg, cp_type_quals (arg) | cp_type_quals (t),
-                      complain);
+                      complain | tf_ignore_bad_quals);
                  }
                else if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
                  {
@@ -6459,8 +6457,10 @@ tsubst (t, args, complain, in_decl)
            if (cp_type_quals (t))
              {
                r = tsubst (TYPE_MAIN_VARIANT (t), args, complain, in_decl);
-               r = cp_build_qualified_type_real
-                 (r, cp_type_quals (t), complain);
+               r = cp_build_qualified_type_real
+                 (r, cp_type_quals (t),
+                  complain | (TREE_CODE (t) == TEMPLATE_TYPE_PARM
+                              ? tf_ignore_bad_quals : 0));
              }
            else
              {
@@ -6785,11 +6785,18 @@ tsubst (t, args, complain, in_decl)
              }
          }
 
-       f = make_typename_type (ctx, f, complain & tf_error);
+       f = make_typename_type (ctx, f,
+                               (complain & tf_error) | tf_keep_type_decl);
        if (f == error_mark_node)
          return f;
-       return cp_build_qualified_type_real
-         (f, cp_type_quals (f) | cp_type_quals (t), complain);
+       if (TREE_CODE (f) == TYPE_DECL)
+         {
+           complain |= tf_ignore_bad_quals;
+           f = TREE_TYPE (f);
+         }
+       
+       return cp_build_qualified_type_real
+         (f, cp_type_quals (f) | cp_type_quals (t), complain);
       }
               
     case UNBOUND_CLASS_TEMPLATE:
@@ -8463,12 +8470,28 @@ check_cv_quals_for_unify (strict, arg, parm)
      tree arg;
      tree parm;
 {
+  int arg_quals = cp_type_quals (arg);
+  int parm_quals = cp_type_quals (parm);
+
+  if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM)
+    {
+      /* If the cvr quals of parm will not unify with ARG, they'll be
+        ignored in instantiation, so we have to do the same here.  */
+      if (TREE_CODE (arg) == REFERENCE_TYPE
+         || TREE_CODE (arg) == FUNCTION_TYPE
+         || TREE_CODE (arg) == METHOD_TYPE)
+       parm_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
+      if (!POINTER_TYPE_P (arg) &&
+         TREE_CODE (arg) != TEMPLATE_TYPE_PARM)
+       parm_quals &= ~TYPE_QUAL_RESTRICT;
+    }
+  
   if (!(strict & (UNIFY_ALLOW_MORE_CV_QUAL | UNIFY_ALLOW_OUTER_MORE_CV_QUAL))
-      && !at_least_as_qualified_p (arg, parm))
+      && (arg_quals & parm_quals) != parm_quals)
     return 0;
 
   if (!(strict & (UNIFY_ALLOW_LESS_CV_QUAL | UNIFY_ALLOW_OUTER_LESS_CV_QUAL))
-      && !at_least_as_qualified_p (parm, arg))
+      && (parm_quals & arg_quals) != arg_quals)
     return 0;
 
   return 1;
@@ -9930,6 +9953,27 @@ instantiate_decl (d, defer_ok)
        import_export_decl (d);
     }
 
+  if (!defer_ok)
+    {
+      /* Recheck the substitutions to obtain any warning messages
+        about ignoring cv qualifiers.  */
+      tree gen = DECL_TEMPLATE_RESULT (gen_tmpl);
+      tree type = TREE_TYPE (gen);
+
+      if (TREE_CODE (gen) == FUNCTION_DECL)
+       {
+         tsubst (DECL_ARGUMENTS (gen), args, tf_error | tf_warning, d);
+         tsubst (TYPE_RAISES_EXCEPTIONS (type), args,
+                 tf_error | tf_warning, d);
+         /* Don't simply tsubst the function type, as that will give
+            duplicate warnings about poor parameter qualifications.
+            The function arguments are the same as the decl_arguments
+            without the top level cv qualifiers. */
+         type = TREE_TYPE (type);
+       }
+      tsubst (type, args, tf_error | tf_warning, d);
+    }
+  
   if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d)
       && DECL_INITIAL (d) == NULL_TREE)
     /* We should have set up DECL_INITIAL in instantiate_class_template.  */
index 62f67e7..8b0a198 100644 (file)
@@ -506,9 +506,23 @@ build_cplus_array_type (elt_type, index_type)
 /* Make a variant of TYPE, qualified with the TYPE_QUALS.  Handles
    arrays correctly.  In particular, if TYPE is an array of T's, and
    TYPE_QUALS is non-empty, returns an array of qualified T's.
-   Errors are emitted under control of COMPLAIN. If COMPLAIN is zero,
-   error_mark_node is returned for bad qualifiers.  */
-
+  
+   FLAGS determines how to deal with illformed qualifications. If
+   tf_ignore_bad_quals is set, then bad qualifications are dropped
+   (this is permitted if TYPE was introduced via a typedef or template
+   type parameter). If bad qualifications are dropped and tf_warning
+   is set, then a warning is issued for non-const qualifications.  If
+   tf_ignore_bad_quals is not set and tf_error is not set, we
+   return error_mark_node. Otherwise, we issue an error, and ignore
+   the qualifications.
+
+   Qualification of a reference type is valid when the reference came
+   via a typedef or template type argument. [dcl.ref] No such
+   dispensation is provided for qualifying a function type.  [dcl.fct]
+   DR 295 queries this and the proposed resolution brings it into line
+   with qualifiying a reference.  We implement the DR.  We also behave
+   in a similar manner for restricting non-pointer types.  */
 tree
 cp_build_qualified_type_real (type, type_quals, complain)
      tree type;
@@ -516,6 +530,7 @@ cp_build_qualified_type_real (type, type_quals, complain)
      tsubst_flags_t complain;
 {
   tree result;
+  int bad_quals = TYPE_UNQUALIFIED;
 
   if (type == error_mark_node)
     return type;
@@ -523,32 +538,51 @@ cp_build_qualified_type_real (type, type_quals, complain)
   if (type_quals == cp_type_quals (type))
     return type;
 
-  /* A restrict-qualified pointer type must be a pointer (or reference)
+  /* A reference, fucntion or method type shall not be cv qualified.
+     [dcl.ref], [dct.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);
+    }
+  
+  /* A restrict-qualified type must be a pointer (or reference)
      to object or incomplete type.  */
   if ((type_quals & TYPE_QUAL_RESTRICT)
       && TREE_CODE (type) != TEMPLATE_TYPE_PARM
-      && (!POINTER_TYPE_P (type)
-         || TYPE_PTRMEM_P (type)
-         || TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE))
+      && TREE_CODE (type) != TYPENAME_TYPE
+      && !POINTER_TYPE_P (type))
     {
-      if (complain & tf_error)
-       error ("`%T' cannot be `restrict'-qualified", type);
-      else
-       return error_mark_node;
-
+      bad_quals |= TYPE_QUAL_RESTRICT;
       type_quals &= ~TYPE_QUAL_RESTRICT;
     }
 
-  if (type_quals != TYPE_UNQUALIFIED
-      && TREE_CODE (type) == FUNCTION_TYPE)
+  if (bad_quals == TYPE_UNQUALIFIED)
+    /*OK*/;
+  else if (!(complain & (tf_error | tf_ignore_bad_quals)))
+    return error_mark_node;
+  else
     {
-      if (complain & tf_error)
-       error ("`%T' cannot be `const'-, `volatile'-, or `restrict'-qualified", type);
-      else
-       return error_mark_node;
-      type_quals = TYPE_UNQUALIFIED;
+      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 ("`%V' qualifiers cannot be applied to `%T'",
+                  bad_type, type);
+         else if (complain & tf_warning)
+           warning ("ignoring `%V' qualifiers on `%T'", bad_type, type);
+       }
     }
-  else if (TREE_CODE (type) == ARRAY_TYPE)
+  
+  if (TREE_CODE (type) == ARRAY_TYPE)
     {
       /* In C++, the qualification really applies to the array element
         type.  Obtain the appropriately qualified element type.  */
@@ -590,7 +624,7 @@ cp_build_qualified_type_real (type, type_quals, complain)
     {
       /* For a pointer-to-member type, we can't just return a
         cv-qualified version of the RECORD_TYPE.  If we do, we
-        haven't change the field that contains the actual pointer to
+        haven't changed the field that contains the actual pointer to
         a method, and so TYPE_PTRMEMFUNC_FN_TYPE will be wrong.  */
       tree t;
 
@@ -598,7 +632,7 @@ cp_build_qualified_type_real (type, type_quals, complain)
       t = cp_build_qualified_type_real (t, type_quals, complain);
       return build_ptrmemfunc_type (t);
     }
-
+  
   /* Retrieve (or create) the appropriately qualified variant.  */
   result = build_qualified_type (type, type_quals);
 
index 12b65ee..6785c53 100644 (file)
@@ -1,3 +1,10 @@
+2002-02-22  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * g++.dg/template/qualttp19.C: New test.
+       * g++.dg/template/qualttp20.C: New test.
+       * g++.old-deja/g++.jason/report.C: Adjust expected errors
+       * g++.old-deja/g++.other/qual1.C: Likewise.
+
 2002-02-21  Aldy Hernandez  <aldyh@redhat.com>
 
         * gcc.dg/attr-alwaysinline.c: New.
diff --git a/gcc/testsuite/g++.dg/template/qualttp19.C b/gcc/testsuite/g++.dg/template/qualttp19.C
new file mode 100644 (file)
index 0000000..be6676c
--- /dev/null
@@ -0,0 +1,41 @@
+// { dg-do compile }
+
+// Copyright (C) 2001 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 15 Dec 2001 <nathan@codesourcery.com>
+
+// PR 2645
+
+template <typename T>
+struct call_traits
+{
+  public:
+  typedef T type_less_spec;
+};
+
+template <typename T>
+struct call_traits<T&>
+{
+  typedef T type_more_spec;
+};
+
+
+int main()
+{
+  int num;
+  
+   // Two typedefs lead to the instant. of the less spec. ("wrong") template
+  typedef int& r_type;
+  typedef const r_type cr_type;
+  call_traits<cr_type>::type_less_spec var  = num; // { dg-error "" "" }
+  
+   // The explicit type leads to the instantiation of the "correct" one
+  call_traits<const int&>::type_more_spec var2 = num;
+  
+   // As happen with a single typedef!
+  typedef const int& std_cr_type;
+  call_traits<std_cr_type>::type_more_spec var3 = num;
+  
+  
+   // As happen, indeed, without the cv-qualifier
+  call_traits<r_type>::type_more_spec var4;
+}
diff --git a/gcc/testsuite/g++.dg/template/qualttp20.C b/gcc/testsuite/g++.dg/template/qualttp20.C
new file mode 100644 (file)
index 0000000..2c6c714
--- /dev/null
@@ -0,0 +1,33 @@
+// { dg-do compile }
+
+// Copyright (C) 2001 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 15 Dec 2001 <nathan@codesourcery.com>
+
+// PR 2645
+
+struct AS
+{
+  typedef void (myT) ();
+  struct L {};
+  
+};
+
+
+template <typename T> struct B1 : T
+{
+  typedef typename T::L __restrict__ r;// { dg-error "`__restrict' qualifiers cannot" "" }
+  typedef typename T::myT __restrict__ p;// { dg-warning "ignoring `__restrict'" "" }
+  
+  typedef typename T::myT volatile *myvolatile; // { dg-warning "ignoring `volatile'" "" }
+  typename T::myT volatile *a;    // { dg-warning "ignoring `volatile'" "" }
+  myvolatile b;                         // { dg-bogus "ignoring `volatile'" "" { xfail *-*-* } }
+};
+template <typename T> struct B2 : T
+{
+  typedef typename T::myT const *myconst;
+  typename T::myT const *a;
+  myconst b;
+};
+
+B1<AS> b1;     // { dg-error "instantiated" "" }
+B2<AS> b2;
index 4599409..14bc9d8 100644 (file)
@@ -2,6 +2,8 @@
 // GROUPS passed error-reporting
 // Special g++ Options: -Wreturn-type
 
+// DR 295 allows qualification via typedef
+
 template <char C>
 class badoo
 {
@@ -44,7 +46,8 @@ class X{
 };
 
 typedef int const * bart ();
-typedef bart const * const * bar2; // ERROR - qualifiers
+typedef bart const * const * bar2; // ok - constifying qualifiers
+typedef bart volatile * const * bar2v; // WARNING - qualifiers
 
 bar2 baz (X::Y y)
 {                              // ERROR - in this context
index 6120dae..fa2d33f 100644 (file)
@@ -2,13 +2,16 @@
 // Origin: Benjamin Pflugmann <philemon@spin.de>
 // Special g++ Options: -O
 
+// DR 295 allows qualification via typedef
+
 typedef const char *(func_type)();
 
 class
 {
 public:
   func_type *Function;
-  const func_type* function(void) { return Function; } // ERROR - qualifiers
+  const func_type* function(void) { return Function; } // ok constifying
+  volatile func_type* functionv(void); // WARNING - qualifier
 } action;
 
 void work(const char *source)