C++ PATCH for restrict & templates

mark@codesourcery.com mark@codesourcery.com
Fri May 21 15:54:00 GMT 1999


The following patch, inspired by Nathan's submission this morning, 
allows the use of `restrict' with templates, and also improves our
handling of template argument deduction for better standards
compliance.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

1999-05-21  Mark Mitchell  <mark@codesourcery.com>
            Nathan Sidwell  <nathan@acm.org>
	
	* Make-lang.in (cc1plus): Make it depend on gxx.gperf.
	* cp-tree.h: Fix typo in documentation on pointers-to-members.
	(cp_build_qualified_type): Make it a macro.
	(cp_build_qualified_type_real): Declare.
	* decl.c (grokdeclarator): Remove misleading comment.  Avoid
	problem with template parameters and restrict-qualification.
	* gxx.gperf: Replace NORID with RID_UNUSED throughout.
	* hash.h: Regenerated.
	* lex.h (rid): Move RID_FIRST_MODIFIER and RID_LAST_MODIFIER into
	the enumeration.
	(NORID): Remove definition.
	* pt.c (tsubst_aggr_type): Use cp_build_qualified_type_real.
	(tsubst): Likewise.  Remove special handling for FUNCTION_TYPEs.
	(fn_type_unification): Check that the function type resulting from
	the deduction is legal.
	(check_cv_quals_for_unify): Don't handle FUNCTION_TYPEs specially.
	(unify): Use cp_build_qualified_type_real.
	* tree.c (build_cplus_array_type_1): Handle error_marks as inputs.
	(cp_build_qualified_type): Rename to ...
	(cp_build_qualified_type_real): Add additional COMPLAIN parameter
	and modify appropriately.

Index: cp/Make-lang.in
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/Make-lang.in,v
retrieving revision 1.34
diff -u -p -r1.34 Make-lang.in
--- Make-lang.in	1999/04/26 23:50:36	1.34
+++ Make-lang.in	1999/05/21 22:29:15
@@ -120,7 +120,7 @@ CXX_SRCS = $(srcdir)/cp/call.c $(srcdir)
  $(srcdir)/cp/repo.c $(srcdir)/cp/semantics.c
 
 cc1plus$(exeext): $(P) $(CXX_SRCS) $(LIBDEPS) stamp-objlist c-common.o c-pragma.o \
-	$(srcdir)/cp/cp-tree.h $(srcdir)/cp/cp-tree.def hash.o
+	$(srcdir)/cp/cp-tree.h $(srcdir)/cp/cp-tree.def $(srcdir)/cp/gxx.gperf hash.o
 	cd cp; $(MAKE) $(FLAGS_TO_PASS) $(CXX_FLAGS_TO_PASS) ../cc1plus$(exeext)
 #
 # Build hooks:
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.233
diff -u -p -r1.233 cp-tree.h
--- cp-tree.h	1999/05/20 10:44:33	1.233
+++ cp-tree.h	1999/05/21 22:29:17
@@ -1721,7 +1721,7 @@ extern int flag_new_for_scope;
    non-virtual function.  Of course, `&f__2B2' is the name of that
    function.
 
-   (Of course, the exactl values may differ depending on the mangling
+   (Of course, the exact values may differ depending on the mangling
    scheme, sizes of types, and such.).  */
      
 /* Get the POINTER_TYPE to the METHOD_TYPE associated with this
@@ -2100,7 +2100,6 @@ extern void check_function_format		PROTO
 /* Print an error message for invalid operands to arith operation CODE.
    NOP_EXPR is used as a special case (see truthvalue_conversion).  */
 extern void binary_op_error                     PROTO((enum tree_code));
-extern tree cp_build_qualified_type             PROTO((tree, int));
 extern tree canonical_type_variant              PROTO((tree));
 extern void c_expand_expr_stmt                  PROTO((tree));
 /* Validate the expression after `case' and apply default promotions.  */
@@ -3387,6 +3386,9 @@ extern int is_dummy_object			PROTO((tree
 extern tree search_tree                         PROTO((tree, tree (*)(tree)));
 extern int cp_valid_lang_attribute		PROTO((tree, tree, tree, tree));
 extern tree make_ptrmem_cst                     PROTO((tree, tree));
+extern tree cp_build_qualified_type_real        PROTO((tree, int, int));
+#define cp_build_qualified_type(TYPE, QUALS) \
+  cp_build_qualified_type_real ((TYPE), (QUALS), /*complain=*/1)
 
 #define scratchalloc expralloc
 #define scratch_tree_cons expr_tree_cons
Index: cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.360
diff -u -p -r1.360 decl.c
--- decl.c	1999/05/20 18:10:25	1.360
+++ decl.c	1999/05/21 22:29:26
@@ -11650,9 +11650,11 @@ grokdeclarator (declarator, declspecs, d
     if (RIDBIT_SETP (RID_STATIC, specbits))
       DECL_THIS_STATIC (decl) = 1;
 
-    /* Record constancy and volatility.  */
-    /* FIXME: Disallow `restrict' pointer-to-member declarations.  */
-    c_apply_type_quals_to_decl (type_quals, decl);
+    /* Record constancy and volatility.  There's no need to do this
+       when processing a template; we'll do this for the instantiated
+       declaration based on the type of DECL.  */
+    if (!processing_template_decl)
+      c_apply_type_quals_to_decl (type_quals, decl);
 
     return decl;
   }
Index: cp/gxx.gperf
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/gxx.gperf,v
retrieving revision 1.8
diff -u -p -r1.8 gxx.gperf
--- gxx.gperf	1999/04/22 17:36:44	1.8
+++ gxx.gperf	1999/05/21 22:29:27
@@ -3,109 +3,109 @@
 %}
 struct resword { const char *name; short token; enum rid rid;};
 %%
-__alignof, ALIGNOF, NORID
-__alignof__, ALIGNOF, NORID
-__asm, ASM_KEYWORD, NORID
-__asm__, ASM_KEYWORD, NORID
-__attribute, ATTRIBUTE, NORID
-__attribute__, ATTRIBUTE, NORID
+__alignof, ALIGNOF, RID_UNUSED
+__alignof__, ALIGNOF, RID_UNUSED
+__asm, ASM_KEYWORD, RID_UNUSED
+__asm__, ASM_KEYWORD, RID_UNUSED
+__attribute, ATTRIBUTE, RID_UNUSED
+__attribute__, ATTRIBUTE, RID_UNUSED
 __complex, TYPESPEC, RID_COMPLEX
 __complex__, TYPESPEC, RID_COMPLEX
 __const, CV_QUALIFIER, RID_CONST
 __const__, CV_QUALIFIER, RID_CONST
-__extension__, EXTENSION, NORID
-__imag, IMAGPART, NORID
-__imag__, IMAGPART, NORID
+__extension__, EXTENSION, RID_UNUSED
+__imag, IMAGPART, RID_UNUSED
+__imag__, IMAGPART, RID_UNUSED
 __inline, SCSPEC, RID_INLINE
 __inline__, SCSPEC, RID_INLINE
-__label__, LABEL, NORID
+__label__, LABEL, RID_UNUSED
 __null, CONSTANT, RID_NULL
-__real, REALPART, NORID
-__real__, REALPART, NORID
+__real, REALPART, RID_UNUSED
+__real__, REALPART, RID_UNUSED
 __restrict, CV_QUALIFIER, RID_RESTRICT
 __restrict__, CV_QUALIFIER, RID_RESTRICT
 __signature__, AGGR, RID_SIGNATURE	/* Extension */,
 __signed, TYPESPEC, RID_SIGNED
 __signed__, TYPESPEC, RID_SIGNED
-__sigof__, SIGOF, NORID		/* Extension */,
-__typeof, TYPEOF, NORID
-__typeof__, TYPEOF, NORID
+__sigof__, SIGOF, RID_UNUSED		/* Extension */,
+__typeof, TYPEOF, RID_UNUSED
+__typeof__, TYPEOF, RID_UNUSED
 __volatile, CV_QUALIFIER, RID_VOLATILE
 __volatile__, CV_QUALIFIER, RID_VOLATILE
 __wchar_t, TYPESPEC, RID_WCHAR  /* Unique to ANSI C++ */,
-asm, ASM_KEYWORD, NORID,
-and, ANDAND, NORID,
-and_eq, ASSIGN, NORID,
+asm, ASM_KEYWORD, RID_UNUSED,
+and, ANDAND, RID_UNUSED,
+and_eq, ASSIGN, RID_UNUSED,
 auto, SCSPEC, RID_AUTO,
-bitand, '&', NORID,
-bitor, '|', NORID,
+bitand, '&', RID_UNUSED,
+bitor, '|', RID_UNUSED,
 bool, TYPESPEC, RID_BOOL,
-break, BREAK, NORID,
-case, CASE, NORID,
-catch, CATCH, NORID,
+break, BREAK, RID_UNUSED,
+case, CASE, RID_UNUSED,
+catch, CATCH, RID_UNUSED,
 char, TYPESPEC, RID_CHAR,
 class, AGGR, RID_CLASS,
-compl, '~', NORID,
+compl, '~', RID_UNUSED,
 const, CV_QUALIFIER, RID_CONST,
-const_cast, CONST_CAST, NORID,
-continue, CONTINUE, NORID,
-default, DEFAULT, NORID,
-delete, DELETE, NORID,
-do, DO, NORID,
+const_cast, CONST_CAST, RID_UNUSED,
+continue, CONTINUE, RID_UNUSED,
+default, DEFAULT, RID_UNUSED,
+delete, DELETE, RID_UNUSED,
+do, DO, RID_UNUSED,
 double, TYPESPEC, RID_DOUBLE,
-dynamic_cast, DYNAMIC_CAST, NORID,
-else, ELSE, NORID,
-enum, ENUM, NORID,
+dynamic_cast, DYNAMIC_CAST, RID_UNUSED,
+else, ELSE, RID_UNUSED,
+enum, ENUM, RID_UNUSED,
 explicit, SCSPEC, RID_EXPLICIT,
 export, SCSPEC, RID_EXPORT,
 extern, SCSPEC, RID_EXTERN,
-false, CXX_FALSE, NORID,
+false, CXX_FALSE, RID_UNUSED,
 float, TYPESPEC, RID_FLOAT,
-for, FOR, NORID,
+for, FOR, RID_UNUSED,
 friend, SCSPEC, RID_FRIEND,
-goto, GOTO, NORID,
-if, IF, NORID,
+goto, GOTO, RID_UNUSED,
+if, IF, RID_UNUSED,
 inline, SCSPEC, RID_INLINE,
 int, TYPESPEC, RID_INT,
 long, TYPESPEC, RID_LONG,
 mutable, SCSPEC, RID_MUTABLE,
-namespace, NAMESPACE, NORID,
-new, NEW, NORID,
-not, '!', NORID,
-not_eq, EQCOMPARE, NORID,
-operator, OPERATOR, NORID,
-or, OROR, NORID,
-or_eq, ASSIGN, NORID,
+namespace, NAMESPACE, RID_UNUSED,
+new, NEW, RID_UNUSED,
+not, '!', RID_UNUSED,
+not_eq, EQCOMPARE, RID_UNUSED,
+operator, OPERATOR, RID_UNUSED,
+or, OROR, RID_UNUSED,
+or_eq, ASSIGN, RID_UNUSED,
 private, VISSPEC, RID_PRIVATE,
 protected, VISSPEC, RID_PROTECTED,
 public, VISSPEC, RID_PUBLIC,
 register, SCSPEC, RID_REGISTER,
-reinterpret_cast, REINTERPRET_CAST, NORID,
-return, RETURN_KEYWORD, NORID,
+reinterpret_cast, REINTERPRET_CAST, RID_UNUSED,
+return, RETURN_KEYWORD, RID_UNUSED,
 short, TYPESPEC, RID_SHORT,
 signature, AGGR, RID_SIGNATURE	/* Extension */,
 signed, TYPESPEC, RID_SIGNED,
-sigof, SIGOF, NORID		/* Extension */,
-sizeof, SIZEOF, NORID,
+sigof, SIGOF, RID_UNUSED		/* Extension */,
+sizeof, SIZEOF, RID_UNUSED,
 static, SCSPEC, RID_STATIC,
-static_cast, STATIC_CAST, NORID,
+static_cast, STATIC_CAST, RID_UNUSED,
 struct, AGGR, RID_RECORD,
-switch, SWITCH, NORID,
+switch, SWITCH, RID_UNUSED,
 template, TEMPLATE, RID_TEMPLATE,
-this, THIS, NORID,
-throw, THROW, NORID,
-true, CXX_TRUE, NORID,
-try, TRY, NORID,
+this, THIS, RID_UNUSED,
+throw, THROW, RID_UNUSED,
+true, CXX_TRUE, RID_UNUSED,
+try, TRY, RID_UNUSED,
 typedef, SCSPEC, RID_TYPEDEF,
-typename, TYPENAME_KEYWORD, NORID,
-typeid, TYPEID, NORID,
-typeof, TYPEOF, NORID,
+typename, TYPENAME_KEYWORD, RID_UNUSED,
+typeid, TYPEID, RID_UNUSED,
+typeof, TYPEOF, RID_UNUSED,
 union, AGGR, RID_UNION,
 unsigned, TYPESPEC, RID_UNSIGNED,
-using, USING, NORID,
+using, USING, RID_UNUSED,
 virtual, SCSPEC, RID_VIRTUAL,
 void, TYPESPEC, RID_VOID,
 volatile, CV_QUALIFIER, RID_VOLATILE,
-while, WHILE, NORID,
-xor, '^', NORID,
-xor_eq, ASSIGN, NORID,
+while, WHILE, RID_UNUSED,
+xor, '^', RID_UNUSED,
+xor_eq, ASSIGN, RID_UNUSED,
Index: cp/lex.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/lex.h,v
retrieving revision 1.6
diff -u -p -r1.6 lex.h
--- lex.h	1998/12/16 21:15:40	1.6
+++ lex.h	1999/05/21 22:29:27
@@ -43,8 +43,9 @@ enum rid
   /* This is where grokdeclarator starts its search when setting the specbits.
      The first seven are in the order of most frequently used, as found
      building libg++.  */
+  RID_FIRST_MODIFIER,
 
-  RID_EXTERN,
+  RID_EXTERN = RID_FIRST_MODIFIER,
   RID_CONST,
   RID_LONG,
   RID_TYPEDEF,
@@ -66,6 +67,7 @@ enum rid
   RID_COMPLEX,
   RID_RESTRICT,
 
+  RID_LAST_MODIFIER = RID_RESTRICT,
   /* This is where grokdeclarator ends its search when setting the
      specbits.  */
 
@@ -80,11 +82,6 @@ enum rid
      will have to be changed a little.  */
   RID_MAX
 };
-
-#define NORID RID_UNUSED
-
-#define RID_FIRST_MODIFIER RID_EXTERN
-#define RID_LAST_MODIFIER RID_COMPLEX
 
 /* The type that can represent all values of RIDBIT.  */
 /* We assume that we can stick in at least 32 bits into this.  */
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.302
diff -u -p -r1.302 pt.c
--- pt.c	1999/05/21 09:55:46	1.302
+++ pt.c	1999/05/21 22:29:32
@@ -5311,7 +5311,8 @@ tsubst_aggr_type (t, args, complain, in_
 	{
 	  tree r = build_ptrmemfunc_type
 	    (tsubst (TYPE_PTRMEMFUNC_FN_TYPE (t), args, complain, in_decl));
-	  return cp_build_qualified_type (r, TYPE_QUALS (t));
+	  return cp_build_qualified_type_real (r, TYPE_QUALS (t),
+					       complain);
 	}
 
       /* else fall through */
@@ -5349,7 +5350,8 @@ tsubst_aggr_type (t, args, complain, in_
 				     entering_scope);
 	  pop_momentary ();
 
-	  return cp_build_qualified_type (r, TYPE_QUALS (t));
+	  return cp_build_qualified_type_real (r, TYPE_QUALS (t),
+					       complain);
 	}
       else 
 	/* This is not a template type, so there's nothing to do.  */
@@ -6208,18 +6210,9 @@ tsubst (t, args, complain, in_decl)
 		  {
 		    my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (arg))
 					== 't', 0);
-
-		    /* If we're not COMPLAINing, don't let an attempt
-		       to qualify a FUNCTION_TYPE reach
-		       cp_build_qualified_type.  That will result in
-		       an error message.  */
-		    if (!complain
-			&& TREE_CODE (arg) == FUNCTION_TYPE
-			&& CP_TYPE_QUALS (t) != TYPE_UNQUALIFIED)
-		      return error_mark_node;
-
-		    return cp_build_qualified_type
-		      (arg, CP_TYPE_QUALS (arg) | CP_TYPE_QUALS (t));
+		    return cp_build_qualified_type_real
+		      (arg, CP_TYPE_QUALS (arg) | CP_TYPE_QUALS (t),
+		       complain);
 		  }
 		else if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
 		  {
@@ -6244,7 +6237,9 @@ tsubst (t, args, complain, in_decl)
 						   argvec, in_decl, 
 						   DECL_CONTEXT (arg),
 						   /*entering_scope=*/0);
-			return cp_build_qualified_type (r, TYPE_QUALS (t));
+			return cp_build_qualified_type_real (r, 
+							     TYPE_QUALS (t),
+							     complain);
 		      }
 		    else
 		      /* We are processing a template argument list.  */ 
@@ -6411,7 +6406,7 @@ tsubst (t, args, complain, in_decl)
 	  r = build_pointer_type (type);
 	else
 	  r = build_reference_type (type);
-	r = cp_build_qualified_type (r, TYPE_QUALS (t));
+	r = cp_build_qualified_type_real (r, TYPE_QUALS (t), complain);
 
 	/* Will this ever be needed for TYPE_..._TO values?  */
 	layout_type (r);
@@ -6553,9 +6548,10 @@ tsubst (t, args, complain, in_decl)
 	f = make_typename_type (ctx, f);
 	if (f == error_mark_node)
 	  return f;
-	return cp_build_qualified_type (f, 
-					CP_TYPE_QUALS (f) 
-					| CP_TYPE_QUALS (t));
+	return cp_build_qualified_type_real (f, 
+					     CP_TYPE_QUALS (f) 
+					     | CP_TYPE_QUALS (t),
+					     complain);
       }
 
     case INDIRECT_REF:
@@ -7388,6 +7384,7 @@ fn_type_unification (fn, explicit_targs,
 {
   tree parms;
   tree fntype;
+  int result;
 
   my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);
   
@@ -7446,9 +7443,25 @@ fn_type_unification (fn, explicit_targs,
      because the standard doesn't seem to explicitly prohibit it.  Our
      callers must be ready to deal with unification failures in any
      event.  */
-  return type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn), 
-				targs, parms, args, /*subr=*/0,
-				strict, /*allow_incomplete*/1);
+  result = type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn), 
+				  targs, parms, args, /*subr=*/0,
+				  strict, /*allow_incomplete*/1);
+
+  if (result == 0) 
+    /* All is well so far.  Now, check:
+       
+       [temp.deduct] 
+       
+       When all template arguments have been deduced, all uses of
+       template parameters in nondeduced contexts are replaced with
+       the corresponding deduced argument values.  If the
+       substitution results in an invalid type, as described above,
+       type deduction fails.  */
+    if (tsubst (TREE_TYPE (fn), targs, /*complain=*/0, NULL_TREE)
+	== error_mark_node)
+      return 1;
+
+  return result;
 }
 
 /* Adjust types before performing type deduction, as described in
@@ -8040,11 +8053,6 @@ check_cv_quals_for_unify (strict, arg, p
       && !at_least_as_qualified_p (parm, arg))
     return 0;
 
-  /* Don't allow unification to create a qualified function type.  */
-  if (TREE_CODE (arg) == FUNCTION_TYPE 
-      && CP_TYPE_QUALS (parm) != TYPE_UNQUALIFIED)
-    return 0;
-
   return 1;
 }
 
@@ -8198,9 +8206,12 @@ unify (tparms, targs, parm, arg, strict)
 	  /* Consider the case where ARG is `const volatile int' and
 	     PARM is `const T'.  Then, T should be `volatile int'.  */
 	  arg = 
-	    cp_build_qualified_type (arg,
-				     CP_TYPE_QUALS (arg) 
-				     & ~CP_TYPE_QUALS (parm));
+	    cp_build_qualified_type_real (arg,
+					  CP_TYPE_QUALS (arg) 
+					  & ~CP_TYPE_QUALS (parm),
+					  /*complain=*/0);
+	  if (arg == error_mark_node)
+	    return 1;
 	}
 
       /* Simple cases: Value already set, does match or doesn't.  */
Index: cp/tree.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/tree.c,v
retrieving revision 1.113
diff -u -p -r1.113 tree.c
--- tree.c	1999/05/20 10:44:42	1.113
+++ tree.c	1999/05/21 22:29:34
@@ -406,6 +406,9 @@ build_cplus_array_type_1 (elt_type, inde
   register struct obstack *ambient_saveable_obstack = saveable_obstack;
   tree t;
 
+  if (elt_type == error_mark_node || index_type == error_mark_node)
+    return error_mark_node;
+
   /* We need a new one.  If both ELT_TYPE and INDEX_TYPE are permanent,
      make this permanent too.  */
   if (TREE_PERMANENT (elt_type)
@@ -453,13 +456,18 @@ build_cplus_array_type (elt_type, index_
   return t;
 }
 
-/* Make a variant type in the proper way for C/C++, propagating qualifiers
-   down to the element type of an array.  */
+/* 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.  If
+   at attempt is made to qualify a type illegally, and COMPLAIN is
+   non-zero, an error is issued.  If COMPLAIN is zero, error_mark_node
+   is returned.  */
 
 tree
-cp_build_qualified_type (type, type_quals)
+cp_build_qualified_type_real (type, type_quals, complain)
      tree type;
      int type_quals;
+     int complain;
 {
   if (type == error_mark_node)
     return type;
@@ -467,29 +475,40 @@ cp_build_qualified_type (type, type_qual
   /* A restrict-qualified pointer 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))
     {
-      cp_error ("`%T' cannot be `restrict'-qualified", type);
+      if (complain)
+	cp_error ("`%T' cannot be `restrict'-qualified", type);
+      else
+	return error_mark_node;
+
       type_quals &= ~TYPE_QUAL_RESTRICT;
     }
 
   if (type_quals != TYPE_UNQUALIFIED
       && TREE_CODE (type) == FUNCTION_TYPE)
     {
-      cp_error ("`%T' cannot be `const'-, `volatile'-, or `restrict'-qualified", type);
+      if (complain)
+	cp_error ("`%T' cannot be `const'-, `volatile'-, or `restrict'-qualified", type);
+      else
+	return error_mark_node;
       type_quals = TYPE_UNQUALIFIED;
     }
   else if (TREE_CODE (type) == ARRAY_TYPE)
     {
       tree real_main_variant = TYPE_MAIN_VARIANT (type);
-
+      tree element_type = cp_build_qualified_type_real (TREE_TYPE (type),
+							type_quals,
+							complain);
       push_obstacks (TYPE_OBSTACK (real_main_variant),
 		     TYPE_OBSTACK (real_main_variant));
-      type = build_cplus_array_type_1 (cp_build_qualified_type 
-				       (TREE_TYPE (type), type_quals),
+      type = build_cplus_array_type_1 (element_type,
 				       TYPE_DOMAIN (type));
+      if (type == error_mark_node)
+	return error_mark_node;
 
       /* TYPE must be on same obstack as REAL_MAIN_VARIANT.  If not,
 	 make a copy.  (TYPE might have come from the hash table and


More information about the Gcc-patches mailing list