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]

C++ PATCH: Implement type-computation for non-dependent expressions


The standard says that we have to compute the types of expressions in
templates, where possible.  For example, we have to know that in:

  struct A { template <int I> void f(); };
  struct B { int f; };
  A* g(int);
  B* g(double);
  template <typename T> void h () { g(2)->f<3>(); }

"f<int>" is a template, and a not something involving less-than and
greater-than operators.  In other words, we have to compute the type
of "g(2)" in order to parse the expression!

This patch implements that functionality.  

It also fixes up several places where we accepted invalid programs; my
favorite is:

  template <int> struct S1{};
  struct S2 { int i; };
  template <class T>
  void f(S2 s2) {
    S1<s2.i> s1;
  }

which is in a test-case I contributed!  Of course, "s2.i" is not a
valid template argument -- and now we notice that.

Tested on i686-pc-linux-gnu, applied on the mainline.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2003-07-08  Mark Mitchell  <mark@codesourcery.com>

	* fold-const.c (make_range): Do not access operand 1 for a
	zero-operand operator.

2003-07-08  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.def (NON_DEPENDENT_EXPR): New node.
	* cp-tree.h (build_call_from_tree): Remove.
	(build_member_call): Likewise.
	(dependent_template_arg_p): Remove.
	(any_dependent_template_arguments_p): New function.
	(dependent_template_id_p): Likewise.
	(any_type_dependent_arguments_p): Likewise.
	(build_non_dependent_expr): Likewise.
	(build_non_dependent_args): Likewise.
	(build_x_compound_expr): Adjust prototype.
	* call.c (build_new_method_call): Handle non-dependent expressions
	correctly.
	* decl2.c (grok_array_decl): Likewise.
	(build_offset_ref_call_from_tree): Likewise.
	(build_call_from_tree): Remove.
	* error.c (dump_decl): Handle NON_DEPENDENT_EXPR.
	(dump_expr): Likewise.
	* init.c (build_member_call): Remove.
	* mangle.c (write_expression): Update handling for template-ids.
	* parser.c (cp_parser_primary_expression): Use
	any_dependent_template_arguments_p.  Update constant-expression
	handling.
	(cp_parser_postfix_expression): Use
	any_type_dependent_arguments_p.  Simplify call processing.
	(cp_parser_unary_expression): Simplify.
	(cp_parser_expression): Adjust for changes to
	build_x_compound_expr.
	(cp_parser_template_argument): Implement standard-conforming
	parsing of non-type template arguments.
	(cp_parser_direct_declarator): Use
	cp_parser_fold_non_dependent_expr.
	(cp_parser_fold_non_dependent_expr): New function.
	(cp_parser_next_token_ends_template_argument_p): Likewise.
	* pt.c (convert_template_argument): Do not call
	maybe_fold_nontype_arg.
	(tsubst_baselink): Likewise.
	(tsubst_copy_and_build): Share common code.  Make sizeof/alignof
	processing work correctly for non-dependent expressions.  Adjust
	handling of COMPOUND_EXPR.  Simplify call processing.
	(value_dependent_expression_p): Deal with functional casts and
	sizeof/alignof correctly.
	(type_dependent_expression_p): Handle overloaded functions.
	(any_type_dependent_arguments_p): New function.
	(any_dependent_template_arguments_p): Likewise.
	(dependent_template_p): Treat SCOPE_REFs as dependent.
	(dependent_template_id_p): Simplify.
	(build_non_dependent_expr): New function.
	(build_non_dependent_args): Likewise.
	* semantics.c (finish_stmt_expr): Don't make dependent
	statement-expresions have void type.
	(finish_call_expr): Handle non-dependent expressions
	correctly.
	* tree.c (lvalue_p_1): Treat NON_DEPENDENT_EXPRs as lvalues.
	* typeck.c (cxx_sizeof_or_alignof_type): Give the expression
	type size_t, even in templates.
	(expr_sizeof): Likewise.
	(finish_class_member_access_expr): Handle non-dependent expressions
	correctly.
	(build_x_indirect_ref): Likewise.
	(build_x_binary_op): Likewise.
	(build_x_unary_op): Likewise.
	(build_x_conditional_expr): Likewise.
	(build_x_compound_expr): Likewise.
	* typeck2.c (build_x_arrow): Likewise.

2003-07-08  Mark Mitchell  <mark@codesourcery.com>

	* g++.dg/abi/mangle17.C: Make sure template expressions are
	dependent.
	* g++.dg/abi/mangle4.C: Mark erroneous casts.
	* g++.dg/debug/debug7.C: Mark erronous new-declarator.
	* g++.dg/opt/stack1.C: Remove erroneous code.
	* g++.dg/parse/template7.C: New test.
	* g++.dg/template/dependent-expr1.C: Mark erroneous code.
	* g++.old-deja/g++.pt/crash4.C: Likewise.

2003-07-09  Mark Mitchell  <mark@codesourcery.com>

	* gcj/array.h (JvPrimClass): Don't parenthesize the output.

Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.277
diff -c -5 -p -r1.277 fold-const.c
*** fold-const.c	7 Jul 2003 19:11:55 -0000	1.277
--- fold-const.c	9 Jul 2003 08:30:13 -0000
*************** make_range (tree exp, int *pin_p, tree *
*** 2906,2916 ****
      {
        code = TREE_CODE (exp);
  
        if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
  	{
! 	  arg0 = TREE_OPERAND (exp, 0);
  	  if (TREE_CODE_CLASS (code) == '<'
  	      || TREE_CODE_CLASS (code) == '1'
  	      || TREE_CODE_CLASS (code) == '2')
  	    type = TREE_TYPE (arg0);
  	  if (TREE_CODE_CLASS (code) == '2'
--- 2906,2917 ----
      {
        code = TREE_CODE (exp);
  
        if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
  	{
! 	  if (first_rtl_op (code) > 0)
! 	    arg0 = TREE_OPERAND (exp, 0);
  	  if (TREE_CODE_CLASS (code) == '<'
  	      || TREE_CODE_CLASS (code) == '1'
  	      || TREE_CODE_CLASS (code) == '2')
  	    type = TREE_TYPE (arg0);
  	  if (TREE_CODE_CLASS (code) == '2'
Index: cp/ChangeLog
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/ChangeLog,v
retrieving revision 1.3502
diff -c -5 -p -r1.3502 ChangeLog
*** cp/ChangeLog	9 Jul 2003 00:31:14 -0000	1.3502
--- cp/ChangeLog	9 Jul 2003 08:30:21 -0000
*************** Wed Jul  9 02:28:39 CEST 2003  Jan Hubic
*** 208,224 ****
  	resolve_offset_ref.
  	(resolve_args): Do not call resolve_offset_ref.
  	(build_conditional_expr): Likewise.
  	(build_new_method_call): Likewise.
  	* cp-tree.def (OFFSET_REF): Update documentation.
! 	(cp_convert_to_pointer): Update handling of conversions from
  	pointers to members to pointers.
  	(ocp_convert): Do not call resolve_offset_ref.
  	(convert_to_void): Likewise.
  	(build_expr_type_conversion): Likewise.
! 	(delete_sanity): Likewise.
! 	(resolve_offset_ref): Simplify greatly.
  	(build_vec_delete): Do not call resolve_offset_ref.
  	* parser.c (cp_parser_postfix_expression): Call resolve_offset_ref
  	if appropriate.
  	(cp_parser_unary_expression): Use
  	cp_parser_simple_cast_expression.
--- 208,224 ----
  	resolve_offset_ref.
  	(resolve_args): Do not call resolve_offset_ref.
  	(build_conditional_expr): Likewise.
  	(build_new_method_call): Likewise.
  	* cp-tree.def (OFFSET_REF): Update documentation.
! 	* cvt.c (cp_convert_to_pointer): Update handling of conversions from
  	pointers to members to pointers.
  	(ocp_convert): Do not call resolve_offset_ref.
  	(convert_to_void): Likewise.
  	(build_expr_type_conversion): Likewise.
! 	* decl2.c (delete_sanity): Likewise.
! 	* init.c (resolve_offset_ref): Simplify greatly.
  	(build_vec_delete): Do not call resolve_offset_ref.
  	* parser.c (cp_parser_postfix_expression): Call resolve_offset_ref
  	if appropriate.
  	(cp_parser_unary_expression): Use
  	cp_parser_simple_cast_expression.
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.403
diff -c -5 -p -r1.403 call.c
*** cp/call.c	8 Jul 2003 01:38:41 -0000	1.403
--- cp/call.c	9 Jul 2003 08:30:22 -0000
*************** build_call (tree function, tree parms)
*** 323,334 ****
  
     PARMS help to figure out what that NAME really refers to.
  
     BASETYPE_PATH, if non-NULL, contains a chain from the type of INSTANCE
     down to the real instance type to use for access checking.  We need this
!    information to get protected accesses correct.  This parameter is used
!    by build_member_call.
  
     FLAGS is the logical disjunction of zero or more LOOKUP_
     flags.  See cp-tree.h for more info.
  
     If this is all OK, calls build_function_call with the resolved
--- 323,333 ----
  
     PARMS help to figure out what that NAME really refers to.
  
     BASETYPE_PATH, if non-NULL, contains a chain from the type of INSTANCE
     down to the real instance type to use for access checking.  We need this
!    information to get protected accesses correct.
  
     FLAGS is the logical disjunction of zero or more LOOKUP_
     flags.  See cp-tree.h for more info.
  
     If this is all OK, calls build_function_call with the resolved
*************** build_new_method_call (tree instance, tr
*** 4881,4898 ****
--- 4880,4914 ----
    tree call;
    tree fn;
    tree class_type;
    int template_only = 0;
    bool any_viable_p;
+   tree orig_instance;
+   tree orig_fns;
+   tree orig_args;
  
    my_friendly_assert (instance != NULL_TREE, 20020729);
  
    if (error_operand_p (instance) 
        || error_operand_p (fns)
        || args == error_mark_node)
      return error_mark_node;
  
+   orig_instance = instance;
+   orig_fns = fns;
+   orig_args = args;
+ 
+   if (processing_template_decl)
+     {
+       instance = build_non_dependent_expr (instance);
+       if (!BASELINK_P (fns)
+ 	  && TREE_CODE (fns) != PSEUDO_DTOR_EXPR
+ 	  && TREE_TYPE (fns) != unknown_type_node)
+ 	fns = build_non_dependent_expr (fns);
+       args = build_non_dependent_args (orig_args);
+     }
+ 
    /* Process the argument list.  */
    user_args = args;
    args = resolve_args (args);
    if (args == error_mark_node)
      return error_mark_node;
*************** build_new_method_call (tree instance, tr
*** 5066,5075 ****
--- 5082,5098 ----
  	 be a static member function, `a' is none-the-less evaluated.  */
        if (!is_dummy_object (instance_ptr) && TREE_SIDE_EFFECTS (instance))
  	call = build (COMPOUND_EXPR, TREE_TYPE (call), instance, call);
      }
  
+   if (processing_template_decl && call != error_mark_node)
+     return build_min (CALL_EXPR,
+ 		      TREE_TYPE (call),
+ 		      build_min_nt (COMPONENT_REF,
+ 				    orig_instance, 
+ 				    orig_fns),
+ 		      orig_args);
    return call;
  }
  
  /* Returns true iff standard conversion sequence ICS1 is a proper
     subsequence of ICS2.  */
Index: cp/cp-tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.def,v
retrieving revision 1.75
diff -c -5 -p -r1.75 cp-tree.def
*** cp/cp-tree.def	4 Jul 2003 05:05:14 -0000	1.75
--- cp/cp-tree.def	9 Jul 2003 08:30:22 -0000
*************** DEFTREECODE (STATIC_CAST_EXPR, "static_c
*** 236,245 ****
--- 236,255 ----
  DEFTREECODE (DYNAMIC_CAST_EXPR, "dynamic_cast_expr", '1', 1)
  DEFTREECODE (DOTSTAR_EXPR, "dotstar_expr", 'e', 2)
  DEFTREECODE (TYPEID_EXPR, "typeid_expr", 'e', 1)
  DEFTREECODE (PSEUDO_DTOR_EXPR, "pseudo_dtor_expr", 'e', 3)
  
+ /* A placeholder for an expression that is not type-dependent, but
+    does occur in a template.  When an expression that is not
+    type-dependent appears in a larger expression, we must compute the
+    type of that larger expression.  That computation would normally
+    modify the original expression, which would change the mangling of
+    that expression if it appeared in a template argument list.  In
+    that situation, we create a NON_DEPENDENT_EXPR to take the place of
+    the original expression.  */
+ DEFTREECODE (NON_DEPENDENT_EXPR, "non_dependent_expr", 'e', 0)
+ 
  /* CTOR_INITIALIZER is a placeholder in template code for a call to
     setup_vtbl_pointer (and appears in all functions, not just ctors).  */
  DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 1)
  DEFTREECODE (TRY_BLOCK, "try_block", 'e', 2)
  DEFTREECODE (EH_SPEC_BLOCK, "eh_spec_block", 'e', 2)
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.870
diff -c -5 -p -r1.870 cp-tree.h
*** cp/cp-tree.h	8 Jul 2003 01:38:41 -0000	1.870
--- cp/cp-tree.h	9 Jul 2003 08:30:22 -0000
*************** struct diagnostic_context;
*** 213,222 ****
--- 213,223 ----
  /* Returns TRUE if generated code should match ABI version N or
     greater is in use.  */
  
  #define abi_version_at_least(N) \
    (flag_abi_version == 0 || flag_abi_version >= (N))
+ 
  
  /* Language-dependent contents of an identifier.  */
  
  struct lang_identifier GTY(())
  {
*************** extern void import_export_vtable (tree, 
*** 3773,3783 ****
  extern void import_export_decl (tree);
  extern void import_export_tinfo	(tree, tree, bool);
  extern void finish_file				(void);
  extern tree build_cleanup			(tree);
  extern tree build_offset_ref_call_from_tree     (tree, tree);
- extern tree build_call_from_tree                (tree, tree, bool);
  extern void set_decl_namespace (tree, tree, bool);
  extern tree current_decl_namespace              (void);
  extern void push_decl_namespace                 (tree);
  extern void pop_decl_namespace                  (void);
  extern void push_scope				(tree);
--- 3774,3783 ----
*************** extern tree build_aggr_init			(tree, tre
*** 3851,3861 ****
  extern tree build_init				(tree, tree, int);
  extern int is_aggr_type				(tree, int);
  extern tree get_aggr_from_typedef		(tree, int);
  extern tree get_type_value			(tree);
  extern tree build_zero_init       		(tree, tree, bool);
- extern tree build_member_call			(tree, tree, tree);
  extern tree build_offset_ref			(tree, tree);
  extern tree resolve_offset_ref			(tree);
  extern tree build_new				(tree, tree, tree, int);
  extern tree build_vec_init			(tree, tree, tree, int);
  extern tree build_x_delete			(tree, int, tree);
--- 3851,3860 ----
*************** extern int problematic_instantiation_cha
*** 3972,3987 ****
  extern void record_last_problematic_instantiation (void);
  extern tree current_instantiation               (void);
  extern tree maybe_get_template_decl_from_type_decl (tree);
  extern int processing_template_parmlist;
  extern bool dependent_type_p                    (tree);
! extern bool dependent_template_arg_p            (tree);
  extern bool dependent_template_p                (tree);
  extern bool type_dependent_expression_p         (tree);
  extern bool value_dependent_expression_p        (tree);
  extern tree resolve_typename_type               (tree, bool);
  extern tree template_for_substitution           (tree);
  
  /* in repo.c */
  extern void repo_template_used (tree);
  extern void repo_template_instantiated (tree, bool);
  extern void init_repo (const char *);
--- 3971,3990 ----
  extern void record_last_problematic_instantiation (void);
  extern tree current_instantiation               (void);
  extern tree maybe_get_template_decl_from_type_decl (tree);
  extern int processing_template_parmlist;
  extern bool dependent_type_p                    (tree);
! extern bool any_dependent_template_arguments_p  (tree);
  extern bool dependent_template_p                (tree);
+ extern bool dependent_template_id_p             (tree, tree);
  extern bool type_dependent_expression_p         (tree);
+ extern bool any_type_dependent_arguments_p      (tree);
  extern bool value_dependent_expression_p        (tree);
  extern tree resolve_typename_type               (tree, bool);
  extern tree template_for_substitution           (tree);
+ extern tree build_non_dependent_expr            (tree);
+ extern tree build_non_dependent_args            (tree);
  
  /* in repo.c */
  extern void repo_template_used (tree);
  extern void repo_template_instantiated (tree, bool);
  extern void init_repo (const char *);
*************** extern tree get_member_function_from_ptr
*** 4265,4275 ****
  extern tree convert_arguments			(tree, tree, tree, int);
  extern tree build_x_binary_op			(enum tree_code, tree, tree);
  extern tree build_x_unary_op			(enum tree_code, tree);
  extern tree unary_complex_lvalue		(enum tree_code, tree);
  extern tree build_x_conditional_expr		(tree, tree, tree);
! extern tree build_x_compound_expr		(tree);
  extern tree build_compound_expr			(tree);
  extern tree build_static_cast			(tree, tree);
  extern tree build_reinterpret_cast		(tree, tree);
  extern tree build_const_cast			(tree, tree);
  extern tree build_c_cast			(tree, tree);
--- 4268,4278 ----
  extern tree convert_arguments			(tree, tree, tree, int);
  extern tree build_x_binary_op			(enum tree_code, tree, tree);
  extern tree build_x_unary_op			(enum tree_code, tree);
  extern tree unary_complex_lvalue		(enum tree_code, tree);
  extern tree build_x_conditional_expr		(tree, tree, tree);
! extern tree build_x_compound_expr		(tree, tree);
  extern tree build_compound_expr			(tree);
  extern tree build_static_cast			(tree, tree);
  extern tree build_reinterpret_cast		(tree, tree);
  extern tree build_const_cast			(tree, tree);
  extern tree build_c_cast			(tree, tree);
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.645
diff -c -5 -p -r1.645 decl2.c
*** cp/decl2.c	9 Jul 2003 00:31:15 -0000	1.645
--- cp/decl2.c	9 Jul 2003 08:30:22 -0000
*************** grokclassfn (tree ctype, tree function, 
*** 396,458 ****
     along the way.  */
  
  tree
  grok_array_decl (tree array_expr, tree index_exp)
  {
!   tree type = TREE_TYPE (array_expr);
!   tree p1, p2, i1, i2;
  
!   if (type == error_mark_node || index_exp == error_mark_node)
      return error_mark_node;
    if (processing_template_decl)
!     return build_min (ARRAY_REF, type ? TREE_TYPE (type) : NULL_TREE,
! 		      array_expr, index_exp);
  
    my_friendly_assert (type, 20030626);
- 
    type = non_reference (type);
  
    /* If they have an `operator[]', use that.  */
    if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
!     return build_new_op (ARRAY_REF, LOOKUP_NORMAL,
  			 array_expr, index_exp, NULL_TREE);
- 
-   /* Otherwise, create an ARRAY_REF for a pointer or array type.  It
-      is a little-known fact that, if `a' is an array and `i' is an
-      int, you can write `i[a]', which means the same thing as `a[i]'.  */
- 
-   if (TREE_CODE (type) == ARRAY_TYPE)
-     p1 = array_expr;
    else
!     p1 = build_expr_type_conversion (WANT_POINTER, array_expr, false);
! 
!   if (TREE_CODE (TREE_TYPE (index_exp)) == ARRAY_TYPE)
!     p2 = index_exp;
!   else
!     p2 = build_expr_type_conversion (WANT_POINTER, index_exp, false);
  
!   i1 = build_expr_type_conversion (WANT_INT | WANT_ENUM, array_expr, false);
!   i2 = build_expr_type_conversion (WANT_INT | WANT_ENUM, index_exp, false);
  
!   if ((p1 && i2) && (i1 && p2))
!     error ("ambiguous conversion for array subscript");
  
!   if (p1 && i2)
!     array_expr = p1, index_exp = i2;
!   else if (i1 && p2)
!     array_expr = p2, index_exp = i1;
!   else
!     {
!       error ("invalid types `%T[%T]' for array subscript",
! 		type, TREE_TYPE (index_exp));
!       return error_mark_node;
!     }
  
!   if (array_expr == error_mark_node || index_exp == error_mark_node)
!     error ("ambiguous conversion for array subscript");
  
!   return build_array_ref (array_expr, index_exp);
  }
  
  /* Given the cast expression EXP, checking out its validity.   Either return
     an error_mark_node if there was an unavoidable error, return a cast to
     void for trying to delete a pointer w/ the value 0, or return the
--- 396,476 ----
     along the way.  */
  
  tree
  grok_array_decl (tree array_expr, tree index_exp)
  {
!   tree type;
!   tree expr;
!   tree orig_array_expr = array_expr;
!   tree orig_index_exp = index_exp;
  
!   if (error_operand_p (array_expr) || error_operand_p (index_exp))
      return error_mark_node;
+ 
    if (processing_template_decl)
!     {
!       if (type_dependent_expression_p (array_expr)
! 	  || type_dependent_expression_p (index_exp))
! 	return build_min_nt (ARRAY_REF, array_expr, index_exp);
!       array_expr = build_non_dependent_expr (array_expr);
!       index_exp = build_non_dependent_expr (index_exp);
!     }
  
+   type = TREE_TYPE (array_expr);
    my_friendly_assert (type, 20030626);
    type = non_reference (type);
  
    /* If they have an `operator[]', use that.  */
    if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
!     expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL,
  			 array_expr, index_exp, NULL_TREE);
    else
!     {
!       tree p1, p2, i1, i2;
  
!       /* Otherwise, create an ARRAY_REF for a pointer or array type.
! 	 It is a little-known fact that, if `a' is an array and `i' is
! 	 an int, you can write `i[a]', which means the same thing as
! 	 `a[i]'.  */
!       if (TREE_CODE (type) == ARRAY_TYPE)
! 	p1 = array_expr;
!       else
! 	p1 = build_expr_type_conversion (WANT_POINTER, array_expr, false);
  
!       if (TREE_CODE (TREE_TYPE (index_exp)) == ARRAY_TYPE)
! 	p2 = index_exp;
!       else
! 	p2 = build_expr_type_conversion (WANT_POINTER, index_exp, false);
  
!       i1 = build_expr_type_conversion (WANT_INT | WANT_ENUM, array_expr, 
! 				       false);
!       i2 = build_expr_type_conversion (WANT_INT | WANT_ENUM, index_exp, 
! 				       false);
! 
!       if ((p1 && i2) && (i1 && p2))
! 	error ("ambiguous conversion for array subscript");
! 
!       if (p1 && i2)
! 	array_expr = p1, index_exp = i2;
!       else if (i1 && p2)
! 	array_expr = p2, index_exp = i1;
!       else
! 	{
! 	  error ("invalid types `%T[%T]' for array subscript",
! 		    type, TREE_TYPE (index_exp));
! 	  return error_mark_node;
! 	}
  
!       if (array_expr == error_mark_node || index_exp == error_mark_node)
! 	error ("ambiguous conversion for array subscript");
  
!       expr = build_array_ref (array_expr, index_exp);
!     }
!   if (processing_template_decl && expr != error_mark_node)
!     return build_min (ARRAY_REF, TREE_TYPE (expr), orig_array_expr, 
! 		      orig_index_exp);
!   return expr;
  }
  
  /* Given the cast expression EXP, checking out its validity.   Either return
     an error_mark_node if there was an unavoidable error, return a cast to
     void for trying to delete a pointer w/ the value 0, or return the
*************** finish_file ()
*** 2947,3038 ****
  
  tree
  build_offset_ref_call_from_tree (tree fn, tree args)
  {
    tree object_addr;
  
!   my_friendly_assert (TREE_CODE (fn) == OFFSET_REF, 20020725);
  
    /* A qualified name corresponding to a bound pointer-to-member is
       represented as an OFFSET_REF:
  
  	struct B { void g(); };
  	void (B::*p)();
  	void B::g() { (this->*p)(); }  */
!   if (TREE_CODE (TREE_OPERAND (fn, 1)) == FIELD_DECL)
!     /* This case should now be handled elsewhere.  */
!     abort ();
!   else
      {
        object_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (fn, 0), 0);
        fn = TREE_OPERAND (fn, 1);
        fn = get_member_function_from_ptrfunc (&object_addr, fn);
        args = tree_cons (NULL_TREE, object_addr, args);
      }
-   return build_function_call (fn, args);
- }
- 
- /* FN indicates the function to call.  Name resolution has been
-    performed on FN.  ARGS are the arguments to the function.  They
-    have already been semantically analyzed.  DISALLOW_VIRTUAL is true
-    if the function call should be determined at compile time, even if
-    FN is virtual.  */
- 
- tree
- build_call_from_tree (tree fn, tree args, bool disallow_virtual)
- {
-   tree template_args;
-   tree template_id;
-   tree f;
-   
-   /* Check to see that name lookup has already been performed.  */
-   my_friendly_assert (TREE_CODE (fn) != OFFSET_REF, 20020725);
-   my_friendly_assert (TREE_CODE (fn) != SCOPE_REF, 20020725);
- 
-   /* In the future all of this should be eliminated.  Instead,
-      name-lookup for a member function should simply return a
-      baselink, instead of a FUNCTION_DECL, TEMPLATE_DECL, or
-      TEMPLATE_ID_EXPR.  */
- 
-   if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
-     {
-       template_id = fn;
-       template_args = TREE_OPERAND (fn, 1);
-       fn = TREE_OPERAND (fn, 0);
-     }
-   else
-     {
-       template_id = NULL_TREE;
-       template_args = NULL_TREE;
-     }
- 
-   f = (TREE_CODE (fn) == OVERLOAD) ? get_first_fn (fn) : fn;
-   /* Make sure we have a baselink (rather than simply a
-      FUNCTION_DECL) for a member function.  */
-   if (current_class_type
-       && ((TREE_CODE (f) == FUNCTION_DECL
- 	   && DECL_FUNCTION_MEMBER_P (f))
- 	  || (DECL_FUNCTION_TEMPLATE_P (f) 
- 	      && DECL_FUNCTION_MEMBER_P (f))))
-     {
-       f = lookup_member (current_class_type, DECL_NAME (f), 
- 			 /*protect=*/1, /*want_type=*/false);
-       if (f)
- 	fn = f;
-     }
- 
-   if (template_id)
-     {
-       if (BASELINK_P (fn))
- 	  BASELINK_FUNCTIONS (fn) = build_nt (TEMPLATE_ID_EXPR, 
- 					      BASELINK_FUNCTIONS (fn),
- 					      template_args);
-       else
- 	fn = template_id;
-     }
  
!   return finish_call_expr (fn, args, disallow_virtual);
  }
  
  /* Returns true if ROOT (a namespace, class, or function) encloses
     CHILD.  CHILD may be either a class type or a namespace.  */
  
--- 2965,3024 ----
  
  tree
  build_offset_ref_call_from_tree (tree fn, tree args)
  {
    tree object_addr;
+   tree orig_fn;
+   tree orig_args;
+   tree expr;
  
!   orig_fn = fn;
!   orig_args = args;
! 
!   if (processing_template_decl)
!     {
!       tree object;
!       tree object_type;
! 
!       my_friendly_assert (TREE_CODE (fn) == DOTSTAR_EXPR
! 			  || TREE_CODE (fn) == MEMBER_REF,
! 			  20030708);
!       if (type_dependent_expression_p (fn)
! 	  || any_type_dependent_arguments_p (args))
! 	return build_min_nt (CALL_EXPR, fn, args);
! 
!       /* Transform the arguments and add the implicit "this"
! 	 parameter.  That must be done before the FN is transformed
! 	 because we depend on the form of FN.  */
!       args = build_non_dependent_args (args);
!       object_type = TREE_TYPE (TREE_OPERAND (fn, 0));
!       if (TREE_CODE (fn) == DOTSTAR_EXPR)
! 	object_type = build_pointer_type (non_reference (object_type));
!       object = build (NON_DEPENDENT_EXPR, object_type);
!       args = tree_cons (NULL_TREE, object, args);
!       /* Now that the arguments are done, transform FN.  */
!       fn = build_non_dependent_expr (fn);
!     }
  
    /* A qualified name corresponding to a bound pointer-to-member is
       represented as an OFFSET_REF:
  
  	struct B { void g(); };
  	void (B::*p)();
  	void B::g() { (this->*p)(); }  */
!   if (TREE_CODE (fn) == OFFSET_REF)
      {
        object_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (fn, 0), 0);
        fn = TREE_OPERAND (fn, 1);
        fn = get_member_function_from_ptrfunc (&object_addr, fn);
        args = tree_cons (NULL_TREE, object_addr, args);
      }
  
!   expr = build_function_call (fn, args);
!   if (processing_template_decl && expr != error_mark_node)
!     return build_min (CALL_EXPR, TREE_TYPE (expr), orig_fn, orig_args);
!   return expr;
  }
  
  /* Returns true if ROOT (a namespace, class, or function) encloses
     CHILD.  CHILD may be either a class type or a namespace.  */
  
Index: cp/error.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/error.c,v
retrieving revision 1.219
diff -c -5 -p -r1.219 error.c
*** cp/error.c	8 Jul 2003 01:38:44 -0000	1.219
--- cp/error.c	9 Jul 2003 08:30:22 -0000
*************** dump_decl (tree t, int flags)
*** 986,995 ****
--- 986,999 ----
  
      case BASELINK:
        dump_decl (BASELINK_FUNCTIONS (t), flags);
        break;
  
+     case NON_DEPENDENT_EXPR:
+       dump_expr (t, flags);
+       break;
+ 
      default:
        sorry_for_unsupported_tree (t);
        /* Fallthrough to error.  */
  
      case ERROR_MARK:
*************** dump_expr (tree t, int flags)
*** 2026,2036 ****
  
      case BASELINK:
        dump_expr (get_first_fn (t), flags & ~TFF_EXPR_IN_PARENS);
        break;
  
!       /* else fall through */
  
        /*  This list is incomplete, but should suffice for now.
  	  It is very important that `sorry' does not call
  	  `report_error_function'.  That could cause an infinite loop.  */
      default:
--- 2030,2044 ----
  
      case BASELINK:
        dump_expr (get_first_fn (t), flags & ~TFF_EXPR_IN_PARENS);
        break;
  
!     case NON_DEPENDENT_EXPR:
!       output_add_string (scratch_buffer, "<expression of type ");
!       dump_type (TREE_TYPE (t), flags);
!       output_add_character (scratch_buffer, '>');
!       break;
  
        /*  This list is incomplete, but should suffice for now.
  	  It is very important that `sorry' does not call
  	  `report_error_function'.  That could cause an infinite loop.  */
      default:
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.329
diff -c -5 -p -r1.329 init.c
*** cp/init.c	8 Jul 2003 01:38:44 -0000	1.329
--- cp/init.c	9 Jul 2003 08:30:22 -0000
*************** get_type_value (tree name)
*** 1335,1495 ****
      return IDENTIFIER_TYPE_VALUE (name);
    else
      return NULL_TREE;
  }
  
- 
- /* This code could just as well go in `class.c', but is placed here for
-    modularity.  */
- 
- /* For an expression of the form TYPE :: NAME (PARMLIST), build
-    the appropriate function call.  */
- 
- tree
- build_member_call (tree type, tree name, tree parmlist)
- {
-   tree t;
-   tree method_name;
-   tree fns;
-   int dtor = 0;
-   tree basetype_path, decl;
- 
-   if (TREE_CODE (name) == TEMPLATE_ID_EXPR
-       && TREE_CODE (type) == NAMESPACE_DECL)
-     {
-       /* 'name' already refers to the decls from the namespace, since we
- 	 hit do_identifier for template_ids.  */
-       method_name = TREE_OPERAND (name, 0);
-       /* FIXME: Since we don't do independent names right yet, the
- 	 name might also be a LOOKUP_EXPR. Once we resolve this to a
- 	 real decl earlier, this can go. This may happen during
- 	 tsubst'ing.  */
-       if (TREE_CODE (method_name) == LOOKUP_EXPR)
- 	{
- 	  method_name = lookup_namespace_name 
- 	    (type, TREE_OPERAND (method_name, 0));
- 	  TREE_OPERAND (name, 0) = method_name;
- 	}
-       my_friendly_assert (is_overloaded_fn (method_name), 980519);
-       return finish_call_expr (name, parmlist, /*disallow_virtual=*/true);
-     }
- 
-   if (DECL_P (name))
-     name = DECL_NAME (name);
- 
-   if (TREE_CODE (type) == NAMESPACE_DECL)
-     return finish_call_expr (lookup_namespace_name (type, name),
- 			     parmlist,
- 			     /*disallow_virtual=*/true);
- 
-   if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
-     {
-       method_name = TREE_OPERAND (name, 0);
-       if (TREE_CODE (method_name) == COMPONENT_REF)
- 	method_name = TREE_OPERAND (method_name, 1);
-       if (is_overloaded_fn (method_name))
- 	method_name = DECL_NAME (OVL_CURRENT (method_name));
-       TREE_OPERAND (name, 0) = method_name;
-     }
-   else
-     method_name = name;
- 
-   if (TREE_CODE (method_name) == BIT_NOT_EXPR)
-     {
-       method_name = TREE_OPERAND (method_name, 0);
-       dtor = 1;
-     }
- 
-   /* This shouldn't be here, and build_member_call shouldn't appear in
-      parse.y!  (mrs)  */
-   if (type && TREE_CODE (type) == IDENTIFIER_NODE
-       && get_aggr_from_typedef (type, 0) == 0)
-     {
-       tree ns = lookup_name (type, 0);
-       if (ns && TREE_CODE (ns) == NAMESPACE_DECL)
- 	return finish_call_expr (lookup_namespace_name (ns, name),
- 				 parmlist,
- 				 /*disallow_virtual=*/true);
-     }
- 
-   if (type == NULL_TREE || ! is_aggr_type (type, 1))
-     return error_mark_node;
- 
-   /* An operator we did not like.  */
-   if (name == NULL_TREE)
-     return error_mark_node;
- 
-   if (dtor)
-     {
-       error ("cannot call destructor `%T::~%T' without object", type,
- 		method_name);
-       return error_mark_node;
-     }
- 
-   decl = maybe_dummy_object (type, &basetype_path);
- 
-   fns = lookup_fnfields (basetype_path, method_name, 0);
-   if (fns)
-     {
-       if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
- 	BASELINK_FUNCTIONS (fns) = build_nt (TEMPLATE_ID_EXPR,
- 					     BASELINK_FUNCTIONS (fns),
- 					     TREE_OPERAND (name, 1));
-       return build_new_method_call (decl, fns, parmlist,
- 				    /*conversion_path=*/NULL_TREE,
- 				    LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
-     }
- 
-   /* Convert 'this' to the specified type to disambiguate conversion
-      to the function's context.  */
-   if (decl == current_class_ref
-       /* ??? this is wrong, but if this conversion is invalid we need to
- 	 defer it until we know whether we are calling a static or
- 	 non-static member function.  Be conservative for now.  */
-       && ACCESSIBLY_UNIQUELY_DERIVED_P (type, current_class_type))
-     {
-       basetype_path = NULL_TREE;
-       decl = build_scoped_ref (decl, type, &basetype_path);
-       if (decl == error_mark_node)
- 	return error_mark_node;
-     }
- 
-   if (constructor_name_p (method_name, type))
-     return build_functional_cast (type, parmlist);
-   if (TREE_CODE (name) == IDENTIFIER_NODE
-       && ((t = lookup_field (TYPE_BINFO (type), name, 1, false))))
-     {
-       if (t == error_mark_node)
- 	return error_mark_node;
-       if (TREE_CODE (t) == FIELD_DECL)
- 	{
- 	  if (is_dummy_object (decl))
- 	    {
- 	      error ("invalid use of non-static field `%D'", t);
- 	      return error_mark_node;
- 	    }
- 	  decl = build (COMPONENT_REF, TREE_TYPE (t), decl, t);
- 	}
-       else if (TREE_CODE (t) == VAR_DECL)
- 	decl = t;
-       else
- 	{
- 	  error ("invalid use of member `%D'", t);
- 	  return error_mark_node;
- 	}
-       if (TYPE_LANG_SPECIFIC (TREE_TYPE (decl)))
- 	return build_new_op (CALL_EXPR, LOOKUP_NORMAL, decl,
- 			     parmlist, NULL_TREE);
-       return build_function_call (decl, parmlist);
-     }
-   else
-     {
-       error ("no method `%T::%D'", type, name);
-       return error_mark_node;
-     }
- }
- 
  /* Build a reference to a member of an aggregate.  This is not a
     C++ `&', but really something which can have its address taken,
     and then act as a pointer to member, for example TYPE :: FIELD
     can have its address taken by saying & TYPE :: FIELD.
  
--- 1335,1344 ----
Index: cp/mangle.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/mangle.c,v
retrieving revision 1.83
diff -c -5 -p -r1.83 mangle.c
*** cp/mangle.c	8 Jul 2003 01:38:44 -0000	1.83
--- cp/mangle.c	9 Jul 2003 08:30:23 -0000
*************** write_expression (tree expr)
*** 2017,2026 ****
--- 2017,2039 ----
  	/* Handle pointers-to-members specially.  */
  	case SCOPE_REF:
  	  write_type (TREE_OPERAND (expr, 0));
  	  if (TREE_CODE (TREE_OPERAND (expr, 1)) == IDENTIFIER_NODE)
  	    write_source_name (TREE_OPERAND (expr, 1));
+ 	  else if (TREE_CODE (TREE_OPERAND (expr, 1)) == TEMPLATE_ID_EXPR)
+ 	    {
+ 	      tree template_id;
+ 	      tree name;
+ 
+ 	      template_id = TREE_OPERAND (expr, 1);
+ 	      name = TREE_OPERAND (template_id, 0);
+ 	      /* FIXME: What about operators?  */
+ 	      my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE,
+ 				  20030707);
+ 	      write_source_name (TREE_OPERAND (template_id, 0));
+ 	      write_template_args (TREE_OPERAND (template_id, 1));
+ 	    }
  	  else
  	    {
  	      /* G++ 3.2 incorrectly put out both the "sr" code and
  		 the nested name of the qualified name.  */
  	      G.need_abi_warning = 1;
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.76
diff -c -5 -p -r1.76 parser.c
*** cp/parser.c	8 Jul 2003 01:38:44 -0000	1.76
--- cp/parser.c	9 Jul 2003 08:30:23 -0000
*************** static void cp_parser_late_parsing_defau
*** 1649,1668 ****
--- 1649,1672 ----
    (cp_parser *, tree);
  static tree cp_parser_sizeof_operand
    (cp_parser *, enum rid);
  static bool cp_parser_declares_only_class_p
    (cp_parser *);
+ static tree cp_parser_fold_non_dependent_expr
+   (tree);
  static bool cp_parser_friend_p
    (tree);
  static cp_token *cp_parser_require
    (cp_parser *, enum cpp_ttype, const char *);
  static cp_token *cp_parser_require_keyword
    (cp_parser *, enum rid, const char *);
  static bool cp_parser_token_starts_function_definition_p 
    (cp_token *);
  static bool cp_parser_next_token_starts_class_definition_p
    (cp_parser *);
+ static bool cp_parser_next_token_ends_template_argument_p
+   (cp_parser *);
  static enum tag_types cp_parser_token_is_class_key
    (cp_token *);
  static void cp_parser_check_class_key
    (enum tag_types, tree type);
  static bool cp_parser_optional_template_keyword
*************** cp_parser_primary_expression (cp_parser 
*** 2379,2389 ****
  
  	default:
  	  cp_parser_error (parser, "expected primary-expression");
  	  return error_mark_node;
  	}
-       /* Fall through.  */
  
        /* An id-expression can start with either an identifier, a
  	 `::' as the beginning of a qualified-id, or the "operator"
  	 keyword.  */
      case CPP_NAME:
--- 2383,2392 ----
*************** cp_parser_primary_expression (cp_parser 
*** 2598,2631 ****
  		/* For a template-id, check to see if the template
  		   arguments are dependent.  */
  		if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
  		  {
  		    tree args = TREE_OPERAND (fns, 1);
! 
! 		    if (args && TREE_CODE (args) == TREE_LIST)
! 		      {
! 			while (args)
! 			  {
! 			    if (dependent_template_arg_p (TREE_VALUE (args)))
! 			      {
! 				dependent_p = true;
! 				break;
! 			      }
! 			    args = TREE_CHAIN (args);
! 			  }
! 		      }
! 		    else if (args && TREE_CODE (args) == TREE_VEC)
! 		      {
! 			int i; 
! 			for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
! 			  if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
! 			    {
! 			      dependent_p = true;
! 			      break;
! 			    }
! 		      }
! 
  		    /* The functions are those referred to by the
  		       template-id.  */
  		    fns = TREE_OPERAND (fns, 0);
  		  }
  
--- 2601,2611 ----
  		/* For a template-id, check to see if the template
  		   arguments are dependent.  */
  		if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
  		  {
  		    tree args = TREE_OPERAND (fns, 1);
! 		    dependent_p = any_dependent_template_arguments_p (args);
  		    /* The functions are those referred to by the
  		       template-id.  */
  		    fns = TREE_OPERAND (fns, 0);
  		  }
  
*************** cp_parser_primary_expression (cp_parser 
*** 2685,2715 ****
  	      }
  
  	    /* Only certain kinds of names are allowed in constant
  	       expression.  Enumerators have already been handled
  	       above.  */
! 	    if (parser->constant_expression_p
  		/* Non-type template parameters of integral or
! 		   enumeration type.  */
! 		&& !(TREE_CODE (decl) == TEMPLATE_PARM_INDEX
! 		     && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)))
  		/* Const variables or static data members of integral
  		   or enumeration types initialized with constant
!                    expressions (or dependent expressions - in this case
!                    the check will be done at instantiation time).  */
! 		&& !(TREE_CODE (decl) == VAR_DECL
! 		     && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))
! 		     && DECL_INITIAL (decl)
!                      && (TREE_CONSTANT (DECL_INITIAL (decl))
!                          || type_dependent_expression_p 
!                          (DECL_INITIAL (decl))
!                          || value_dependent_expression_p 
!                          (DECL_INITIAL (decl)))))
! 	      {
! 		if (!parser->allow_non_constant_expression_p)
! 		  return cp_parser_non_constant_id_expression (decl);
! 		parser->non_constant_expression_p = true;
  	      }
  
  	    if (parser->scope)
  	      {
  		decl = (adjust_result_of_qualified_name_lookup 
--- 2665,2702 ----
  	      }
  
  	    /* Only certain kinds of names are allowed in constant
  	       expression.  Enumerators have already been handled
  	       above.  */
! 	    if (parser->constant_expression_p)
! 	      {
  		/* Non-type template parameters of integral or
! 		   enumeration type are OK.  */
! 		if (TREE_CODE (decl) == TEMPLATE_PARM_INDEX
! 		    && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)))
! 		  ;
  		/* Const variables or static data members of integral
  		   or enumeration types initialized with constant
!                    expressions are OK.  We also accept dependent
! 		   initializers; they may turn out to be constant at
! 		   instantiation-time.  */
! 		else if (TREE_CODE (decl) == VAR_DECL
! 			 && CP_TYPE_CONST_P (TREE_TYPE (decl))
! 			 && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))
! 			 && DECL_INITIAL (decl)
! 			 && (TREE_CONSTANT (DECL_INITIAL (decl))
! 			     || type_dependent_expression_p (DECL_INITIAL 
! 							     (decl))
! 			     || value_dependent_expression_p (DECL_INITIAL 
! 							      (decl))))
! 		  ;
! 		else
! 		  {
! 		    if (!parser->allow_non_constant_expression_p)
! 		      return cp_parser_non_constant_id_expression (decl);
! 		    parser->non_constant_expression_p = true;
! 		  }
  	      }
  
  	    if (parser->scope)
  	      {
  		decl = (adjust_result_of_qualified_name_lookup 
*************** cp_parser_postfix_expression (cp_parser 
*** 3790,3800 ****
  		&& (is_overloaded_fn (postfix_expression)
  		    || DECL_P (postfix_expression)
  		    || TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
  		&& args)
  	      {
- 		tree arg;
  		tree identifier = NULL_TREE;
  		tree functions = NULL_TREE;
  
  		/* Find the name of the overloaded function.  */
  		if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
--- 3777,3786 ----
*************** cp_parser_postfix_expression (cp_parser 
*** 3813,3871 ****
  		/* A call to a namespace-scope function using an
  		   unqualified name.
  
  		   Do Koenig lookup -- unless any of the arguments are
  		   type-dependent.  */
! 		for (arg = args; arg; arg = TREE_CHAIN (arg))
! 		  if (type_dependent_expression_p (TREE_VALUE (arg)))
! 		      break;
! 		if (!arg)
  		  {
  		    postfix_expression 
  		      = lookup_arg_dependent (identifier, functions, args);
  		    if (!postfix_expression)
  		      {
  			/* The unqualified name could not be resolved.  */
  			unqualified_name_lookup_error (identifier);
  			postfix_expression = error_mark_node;
  		      }
- 		    postfix_expression
- 		      = build_call_from_tree (postfix_expression, args, 
- 					      /*diallow_virtual=*/false);
- 		    break;
  		  }
! 		postfix_expression = build_min_nt (LOOKUP_EXPR,
! 						   identifier);
  	      }
  	    else if (idk == CP_PARSER_ID_KIND_UNQUALIFIED 
  		     && TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
  	      {
  		/* The unqualified name could not be resolved.  */
  		unqualified_name_lookup_error (postfix_expression);
  		postfix_expression = error_mark_node;
  		break;
  	      }
  
! 	    /* In the body of a template, no further processing is
! 	       required.  */
! 	    if (processing_template_decl)
  	      {
! 		postfix_expression = build_nt (CALL_EXPR,
! 					       postfix_expression, 
! 					       args);
! 		break;
! 	      }
  
! 	    if (TREE_CODE (postfix_expression) == COMPONENT_REF)
! 	      postfix_expression
! 		= (build_new_method_call 
! 		   (TREE_OPERAND (postfix_expression, 0),
! 		    TREE_OPERAND (postfix_expression, 1),
! 		    args, NULL_TREE, 
! 		    (idk == CP_PARSER_ID_KIND_QUALIFIED 
! 		     ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL)));
! 	    else if (TREE_CODE (postfix_expression) == OFFSET_REF)
  	      postfix_expression = (build_offset_ref_call_from_tree
  				    (postfix_expression, args));
  	    else if (idk == CP_PARSER_ID_KIND_QUALIFIED)
  	      /* A call to a static class member, or a namespace-scope
  		 function.  */
--- 3799,3858 ----
  		/* A call to a namespace-scope function using an
  		   unqualified name.
  
  		   Do Koenig lookup -- unless any of the arguments are
  		   type-dependent.  */
! 		if (!any_type_dependent_arguments_p (args))
  		  {
  		    postfix_expression 
  		      = lookup_arg_dependent (identifier, functions, args);
  		    if (!postfix_expression)
  		      {
  			/* The unqualified name could not be resolved.  */
  			unqualified_name_lookup_error (identifier);
  			postfix_expression = error_mark_node;
+ 			break;
  		      }
  		  }
! 		else
! 		  postfix_expression = build_min_nt (LOOKUP_EXPR,
! 						     identifier);
  	      }
  	    else if (idk == CP_PARSER_ID_KIND_UNQUALIFIED 
  		     && TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
  	      {
  		/* The unqualified name could not be resolved.  */
  		unqualified_name_lookup_error (postfix_expression);
  		postfix_expression = error_mark_node;
  		break;
  	      }
  
! 	    if (TREE_CODE (postfix_expression) == COMPONENT_REF)
  	      {
! 		tree instance = TREE_OPERAND (postfix_expression, 0);
! 		tree fn = TREE_OPERAND (postfix_expression, 1);
  
! 		if (processing_template_decl
! 		    && (type_dependent_expression_p (instance)
! 			|| (!BASELINK_P (fn)
! 			    && TREE_CODE (fn) != FIELD_DECL)
! 			|| any_type_dependent_arguments_p (args)))
! 		  {
! 		    postfix_expression
! 		      = build_min_nt (CALL_EXPR, postfix_expression, args);
! 		    break;
! 		  }
! 		  
! 		postfix_expression
! 		  = (build_new_method_call 
! 		     (instance, fn, args, NULL_TREE, 
! 		      (idk == CP_PARSER_ID_KIND_QUALIFIED 
! 		       ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL)));
! 	      }
! 	    else if (TREE_CODE (postfix_expression) == OFFSET_REF
! 		     || TREE_CODE (postfix_expression) == MEMBER_REF
! 		     || TREE_CODE (postfix_expression) == DOTSTAR_EXPR)
  	      postfix_expression = (build_offset_ref_call_from_tree
  				    (postfix_expression, args));
  	    else if (idk == CP_PARSER_ID_KIND_QUALIFIED)
  	      /* A call to a static class member, or a namespace-scope
  		 function.  */
*************** cp_parser_postfix_expression (cp_parser 
*** 3965,3976 ****
  		   build the SCOPE_REF.  For example;
  
                       struct X { void f(); };
                       template <typename T> void f(T* t) { t->X::f(); }
   
!                    Even though "t" is dependent, "X::f" is not and has 
! 		   except that for a BASELINK there is no need to
  		   include scope information.  */
  
  		/* But we do need to remember that there was an explicit
  		   scope for virtual function calls.  */
  		if (parser->scope)
--- 3952,3963 ----
  		   build the SCOPE_REF.  For example;
  
                       struct X { void f(); };
                       template <typename T> void f(T* t) { t->X::f(); }
   
!                    Even though "t" is dependent, "X::f" is not and has
! 		   been resolved to a BASELINK; there is no need to
  		   include scope information.  */
  
  		/* But we do need to remember that there was an explicit
  		   scope for virtual function calls.  */
  		if (parser->scope)
*************** cp_parser_unary_expression (cp_parser *p
*** 4334,4344 ****
  	{
  	case INDIRECT_REF:
  	  return build_x_indirect_ref (cast_expression, "unary *");
  	  
  	case ADDR_EXPR:
! 	  return build_x_unary_op (ADDR_EXPR, cast_expression);
  	  
  	case PREINCREMENT_EXPR:
  	case PREDECREMENT_EXPR:
  	  if (parser->constant_expression_p)
  	    {
--- 4321,4332 ----
  	{
  	case INDIRECT_REF:
  	  return build_x_indirect_ref (cast_expression, "unary *");
  	  
  	case ADDR_EXPR:
! 	case BIT_NOT_EXPR:
! 	  return build_x_unary_op (unary_operator, cast_expression);
  	  
  	case PREINCREMENT_EXPR:
  	case PREDECREMENT_EXPR:
  	  if (parser->constant_expression_p)
  	    {
*************** cp_parser_unary_expression (cp_parser *p
*** 4352,4364 ****
  	case CONVERT_EXPR:
  	case NEGATE_EXPR:
  	case TRUTH_NOT_EXPR:
  	  return finish_unary_op_expr (unary_operator, cast_expression);
  
- 	case BIT_NOT_EXPR:
- 	  return build_x_unary_op (BIT_NOT_EXPR, cast_expression);
- 
  	default:
  	  abort ();
  	  return error_mark_node;
  	}
      }
--- 4340,4349 ----
*************** cp_parser_assignment_operator_opt (cp_pa
*** 5291,5301 ****
  
  static tree
  cp_parser_expression (cp_parser* parser)
  {
    tree expression = NULL_TREE;
-   bool saw_comma_p = false;
  
    while (true)
      {
        tree assignment_expression;
  
--- 5276,5285 ----
*************** cp_parser_expression (cp_parser* parser)
*** 5304,5352 ****
  	= cp_parser_assignment_expression (parser);
        /* If this is the first assignment-expression, we can just
  	 save it away.  */
        if (!expression)
  	expression = assignment_expression;
-       /* Otherwise, chain the expressions together.  It is unclear why
- 	 we do not simply build COMPOUND_EXPRs as we go.  */
        else
! 	expression = tree_cons (NULL_TREE, 
! 				assignment_expression,
! 				expression);
        /* If the next token is not a comma, then we are done with the
  	 expression.  */
        if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
  	break;
        /* Consume the `,'.  */
        cp_lexer_consume_token (parser->lexer);
-       /* The first time we see a `,', we must take special action
- 	 because the representation used for a single expression is
- 	 different from that used for a list containing the single
- 	 expression.  */
-       if (!saw_comma_p)
- 	{
- 	  /* Remember that this expression has a `,' in it.  */
- 	  saw_comma_p = true;
- 	  /* Turn the EXPRESSION into a TREE_LIST so that we can link
- 	     additional expressions to it.  */
- 	  expression = build_tree_list (NULL_TREE, expression);
- 	}
-     }
- 
-   /* Build a COMPOUND_EXPR to represent the entire expression, if
-      necessary.  We built up the list in reverse order, so we must
-      straighten it out here.  */
-   if (saw_comma_p)
-     {
        /* A comma operator cannot appear in a constant-expression.  */
        if (parser->constant_expression_p)
  	{
  	  if (!parser->allow_non_constant_expression_p)
! 	    return cp_parser_non_constant_expression ("a comma operator");
  	  parser->non_constant_expression_p = true;
  	}
-       expression = build_x_compound_expr (nreverse (expression));
      }
  
    return expression;
  }
  
--- 5288,5314 ----
  	= cp_parser_assignment_expression (parser);
        /* If this is the first assignment-expression, we can just
  	 save it away.  */
        if (!expression)
  	expression = assignment_expression;
        else
! 	expression = build_x_compound_expr (expression,
! 					    assignment_expression);
        /* If the next token is not a comma, then we are done with the
  	 expression.  */
        if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
  	break;
        /* Consume the `,'.  */
        cp_lexer_consume_token (parser->lexer);
        /* A comma operator cannot appear in a constant-expression.  */
        if (parser->constant_expression_p)
  	{
  	  if (!parser->allow_non_constant_expression_p)
! 	    expression 
! 	      = cp_parser_non_constant_expression ("a comma operator");
  	  parser->non_constant_expression_p = true;
  	}
      }
  
    return expression;
  }
  
*************** cp_parser_expression (cp_parser* parser)
*** 5354,5365 ****
  
     constant-expression:
       conditional-expression  
  
    If ALLOW_NON_CONSTANT_P a non-constant expression is silently
!   accepted.  In that case *NON_CONSTANT_P is set to TRUE.  If
!   ALLOW_NON_CONSTANT_P is false, NON_CONSTANT_P should be NULL.  */
  
  static tree
  cp_parser_constant_expression (cp_parser* parser, 
  			       bool allow_non_constant_p,
  			       bool *non_constant_p)
--- 5316,5328 ----
  
     constant-expression:
       conditional-expression  
  
    If ALLOW_NON_CONSTANT_P a non-constant expression is silently
!   accepted.  If ALLOW_NON_CONSTANT_P is true and the expression is not
!   constant, *NON_CONSTANT_P is set to TRUE.  If ALLOW_NON_CONSTANT_P
!   is false, NON_CONSTANT_P should be NULL.  */
  
  static tree
  cp_parser_constant_expression (cp_parser* parser, 
  			       bool allow_non_constant_p,
  			       bool *non_constant_p)
*************** cp_parser_labeled_statement (cp_parser* 
*** 5545,5555 ****
  
  	/* Consume the `case' token.  */
  	cp_lexer_consume_token (parser->lexer);
  	/* Parse the constant-expression.  */
  	expr = cp_parser_constant_expression (parser, 
! 					      /*allow_non_constant=*/false,
  					      NULL);
  	/* Create the label.  */
  	statement = finish_case_label (expr, NULL_TREE);
        }
        break;
--- 5508,5518 ----
  
  	/* Consume the `case' token.  */
  	cp_lexer_consume_token (parser->lexer);
  	/* Parse the constant-expression.  */
  	expr = cp_parser_constant_expression (parser, 
! 					      /*allow_non_constant_p=*/false,
  					      NULL);
  	/* Create the label.  */
  	statement = finish_case_label (expr, NULL_TREE);
        }
        break;
*************** cp_parser_template_argument_list (cp_par
*** 8049,8065 ****
       id-expression
  
     The representation is that of an assignment-expression, type-id, or
     id-expression -- except that the qualified id-expression is
     evaluated, so that the value returned is either a DECL or an
!    OVERLOAD.  */
  
  static tree
  cp_parser_template_argument (cp_parser* parser)
  {
    tree argument;
    bool template_p;
  
    /* There's really no way to know what we're looking at, so we just
       try each alternative in order.  
  
         [temp.arg]
--- 8012,8036 ----
       id-expression
  
     The representation is that of an assignment-expression, type-id, or
     id-expression -- except that the qualified id-expression is
     evaluated, so that the value returned is either a DECL or an
!    OVERLOAD.  
! 
!    Although the standard says "assignment-expression", it forbids
!    throw-expressions or assignments in the template argument.
!    Therefore, we use "conditional-expression" instead.  */
  
  static tree
  cp_parser_template_argument (cp_parser* parser)
  {
    tree argument;
    bool template_p;
+   bool address_p;
+   cp_token *token;
+   cp_parser_id_kind idk;
+   tree qualifying_class;
  
    /* There's really no way to know what we're looking at, so we just
       try each alternative in order.  
  
         [temp.arg]
*************** cp_parser_template_argument (cp_parser* 
*** 8071,8082 ****
       Therefore, we try a type-id first.  */
    cp_parser_parse_tentatively (parser);
    argument = cp_parser_type_id (parser);
    /* If the next token isn't a `,' or a `>', then this argument wasn't
       really finished.  */
!   if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)
!       && cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER))
      cp_parser_error (parser, "expected template-argument");
    /* If that worked, we're done.  */
    if (cp_parser_parse_definitely (parser))
      return argument;
    /* We're still not sure what the argument will be.  */
--- 8042,8052 ----
       Therefore, we try a type-id first.  */
    cp_parser_parse_tentatively (parser);
    argument = cp_parser_type_id (parser);
    /* If the next token isn't a `,' or a `>', then this argument wasn't
       really finished.  */
!   if (!cp_parser_next_token_ends_template_argument_p (parser))
      cp_parser_error (parser, "expected template-argument");
    /* If that worked, we're done.  */
    if (cp_parser_parse_definitely (parser))
      return argument;
    /* We're still not sure what the argument will be.  */
*************** cp_parser_template_argument (cp_parser* 
*** 8086,8097 ****
  				      /*template_keyword_p=*/false,
  				      /*check_dependency_p=*/true,
  				      &template_p);
    /* If the next token isn't a `,' or a `>', then this argument wasn't
       really finished.  */
!   if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)
!       && cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER))
      cp_parser_error (parser, "expected template-argument");
    if (!cp_parser_error_occurred (parser))
      {
        /* Figure out what is being referred to.  */
        argument = cp_parser_lookup_name_simple (parser, argument);
--- 8056,8066 ----
  				      /*template_keyword_p=*/false,
  				      /*check_dependency_p=*/true,
  				      &template_p);
    /* If the next token isn't a `,' or a `>', then this argument wasn't
       really finished.  */
!   if (!cp_parser_next_token_ends_template_argument_p (parser))
      cp_parser_error (parser, "expected template-argument");
    if (!cp_parser_error_occurred (parser))
      {
        /* Figure out what is being referred to.  */
        argument = cp_parser_lookup_name_simple (parser, argument);
*************** cp_parser_template_argument (cp_parser* 
*** 8102,8113 ****
        else if (TREE_CODE (argument) != TEMPLATE_DECL)
  	cp_parser_error (parser, "expected template-name");
      }
    if (cp_parser_parse_definitely (parser))
      return argument;
!   /* It must be an assignment-expression.  */
!   return cp_parser_assignment_expression (parser);
  }
  
  /* Parse an explicit-instantiation.
  
     explicit-instantiation:
--- 8071,8175 ----
        else if (TREE_CODE (argument) != TEMPLATE_DECL)
  	cp_parser_error (parser, "expected template-name");
      }
    if (cp_parser_parse_definitely (parser))
      return argument;
!   /* It must be a non-type argument.  There permitted cases are given
!      in [temp.arg.nontype]:
! 
!      -- an integral constant-expression of integral or enumeration
!         type; or
! 
!      -- the name of a non-type template-parameter; or
! 
!      -- the name of an object or function with external linkage...
! 
!      -- the address of an object or function with external linkage...
! 
!      -- a pointer to member... */
!   /* Look for a non-type template parameter.  */
!   if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
!     {
!       cp_parser_parse_tentatively (parser);
!       argument = cp_parser_primary_expression (parser,
! 					       &idk,
! 					       &qualifying_class);
!       if (TREE_CODE (argument) != TEMPLATE_PARM_INDEX
! 	  || !cp_parser_next_token_ends_template_argument_p (parser))
! 	cp_parser_simulate_error (parser);
!       if (cp_parser_parse_definitely (parser))
! 	return argument;
!     }
!   /* If the next token is "&", the argument must be the address of an
!      object or function with external linkage.  */
!   address_p = cp_lexer_next_token_is (parser->lexer, CPP_AND);
!   if (address_p)
!     cp_lexer_consume_token (parser->lexer);
!   /* See if we might have an id-expression.  */
!   token = cp_lexer_peek_token (parser->lexer);
!   if (token->type == CPP_NAME
!       || token->keyword == RID_OPERATOR
!       || token->type == CPP_SCOPE
!       || token->type == CPP_TEMPLATE_ID
!       || token->type == CPP_NESTED_NAME_SPECIFIER)
!     {
!       cp_parser_parse_tentatively (parser);
!       argument = cp_parser_primary_expression (parser,
! 					       &idk,
! 					       &qualifying_class);
!       if (cp_parser_error_occurred (parser)
! 	  || !cp_parser_next_token_ends_template_argument_p (parser))
! 	cp_parser_abort_tentative_parse (parser);
!       else
! 	{
! 	  if (qualifying_class)
! 	    argument = finish_qualified_id_expr (qualifying_class,
! 						 argument,
! 						 /*done=*/true,
! 						 address_p);
! 	  if (TREE_CODE (argument) == VAR_DECL)
! 	    {
! 	      /* A variable without external linkage might still be a
! 		 valid constant-expression, so no error is issued here
! 		 if the external-linkage check fails.  */
! 	      if (!DECL_EXTERNAL_LINKAGE_P (argument))
! 		cp_parser_simulate_error (parser);
! 	    }
! 	  else if (is_overloaded_fn (argument))
! 	    /* All overloaded functions are allowed; if the external
! 	       linkage test does not pass, an error will be issued
! 	       later.  */
! 	    ;
! 	  else if (address_p
! 		   && (TREE_CODE (argument) == OFFSET_REF 
! 		       || TREE_CODE (argument) == SCOPE_REF))
! 	    /* A pointer-to-member.  */
! 	    ;
! 	  else
! 	    cp_parser_simulate_error (parser);
! 
! 	  if (cp_parser_parse_definitely (parser))
! 	    {
! 	      if (address_p)
! 		argument = build_x_unary_op (ADDR_EXPR, argument);
! 	      return argument;
! 	    }
! 	}
!     }
!   /* If the argument started with "&", there are no other valid
!      alternatives at this point.  */
!   if (address_p)
!     {
!       cp_parser_error (parser, "invalid non-type template argument");
!       return error_mark_node;
!     }
!   /* The argument must be a constant-expression. */
!   argument = cp_parser_constant_expression (parser, 
! 					    /*allow_non_constant_p=*/false,
! 					    /*non_constant_p=*/NULL);
!   /* If it's non-dependent, simplify it.  */
!   return cp_parser_fold_non_dependent_expr (argument);
  }
  
  /* Parse an explicit-instantiation.
  
     explicit-instantiation:
*************** cp_parser_enumerator_definition (cp_pars
*** 8912,8922 ****
      {
        /* Consume the `=' token.  */
        cp_lexer_consume_token (parser->lexer);
        /* Parse the value.  */
        value = cp_parser_constant_expression (parser, 
! 					     /*allow_non_constant=*/false,
  					     NULL);
      }
    else
      value = NULL_TREE;
  
--- 8974,8984 ----
      {
        /* Consume the `=' token.  */
        cp_lexer_consume_token (parser->lexer);
        /* Parse the value.  */
        value = cp_parser_constant_expression (parser, 
! 					     /*allow_non_constant_p=*/false,
  					     NULL);
      }
    else
      value = NULL_TREE;
  
*************** cp_parser_direct_declarator (cp_parser* 
*** 9917,9949 ****
  
  	      bounds 
  		= cp_parser_constant_expression (parser,
  						 /*allow_non_constant=*/true,
  						 &non_constant_p);
! 	      /* If we're in a template, but the constant-expression
! 		 isn't value dependent, simplify it.  We're supposed
! 		 to treat:
! 
! 		   template <typename T> void f(T[1 + 1]);
! 		   template <typename T> void f(T[2]);
! 		   
! 		 as two declarations of the same function, for
! 		 example.  */
! 	      if (processing_template_decl
! 		  && !non_constant_p
! 		  && !value_dependent_expression_p (bounds))
! 		{
! 		  HOST_WIDE_INT saved_processing_template_decl;
! 
! 		  saved_processing_template_decl = processing_template_decl;
! 		  processing_template_decl = 0;
! 		  bounds = tsubst_copy_and_build (bounds, 
! 						  /*args=*/NULL_TREE,
! 						  tf_error,
! 						  /*in_decl=*/NULL_TREE);
! 		  processing_template_decl = saved_processing_template_decl;
! 		}
  	    }
  	  else
  	    bounds = NULL_TREE;
  	  /* Look for the closing `]'.  */
  	  if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"))
--- 9979,9990 ----
  
  	      bounds 
  		= cp_parser_constant_expression (parser,
  						 /*allow_non_constant=*/true,
  						 &non_constant_p);
! 	      if (!non_constant_p)
! 		bounds = cp_parser_fold_non_dependent_expr (bounds);
  	    }
  	  else
  	    bounds = NULL_TREE;
  	  /* Look for the closing `]'.  */
  	  if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"))
*************** cp_parser_declares_only_class_p (cp_pars
*** 14127,14136 ****
--- 14168,14207 ----
       declarator.  */
    return (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
  	  || cp_lexer_next_token_is (parser->lexer, CPP_COMMA));
  }
  
+ /* Simplify EXPR if it is a non-dependent expression.  Returns the
+    (possibly simplified) expression.  */
+ 
+ static tree
+ cp_parser_fold_non_dependent_expr (tree expr)
+ {
+   /* If we're in a template, but EXPR isn't value dependent, simplify
+      it.  We're supposed to treat:
+      
+        template <typename T> void f(T[1 + 1]);
+        template <typename T> void f(T[2]);
+ 		   
+      as two declarations of the same function, for example.  */
+   if (processing_template_decl
+       && !type_dependent_expression_p (expr)
+       && !value_dependent_expression_p (expr))
+     {
+       HOST_WIDE_INT saved_processing_template_decl;
+ 
+       saved_processing_template_decl = processing_template_decl;
+       processing_template_decl = 0;
+       expr = tsubst_copy_and_build (expr,
+ 				    /*args=*/NULL_TREE,
+ 				    tf_error,
+ 				    /*in_decl=*/NULL_TREE);
+       processing_template_decl = saved_processing_template_decl;
+     }
+   return expr;
+ }
+ 
  /* DECL_SPECIFIERS is the representation of a decl-specifier-seq.
     Returns TRUE iff `friend' appears among the DECL_SPECIFIERS.  */
  
  static bool
  cp_parser_friend_p (tree decl_specifiers)
*************** cp_parser_next_token_starts_class_defini
*** 14272,14281 ****
--- 14343,14364 ----
  
    token = cp_lexer_peek_token (parser->lexer);
    return (token->type == CPP_OPEN_BRACE || token->type == CPP_COLON);
  }
  
+ /* Returns TRUE iff the next token is the "," or ">" ending a
+    template-argument.  */
+ 
+ static bool
+ cp_parser_next_token_ends_template_argument_p (cp_parser *parser)
+ {
+   cp_token *token;
+ 
+   token = cp_lexer_peek_token (parser->lexer);
+   return (token->type == CPP_COMMA || token->type == CPP_GREATER);
+ }
+  
  /* Returns the kind of tag indicated by TOKEN, if it is a class-key,
     or none_type otherwise.  */
  
  static enum tag_types
  cp_parser_token_is_class_key (cp_token* token)
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.716
diff -c -5 -p -r1.716 pt.c
*** cp/pt.c	8 Jul 2003 15:35:48 -0000	1.716
--- cp/pt.c	9 Jul 2003 08:30:24 -0000
*************** static tree for_each_template_parm_r (tr
*** 165,175 ****
  static tree copy_default_args_to_explicit_spec_1 (tree, tree);
  static void copy_default_args_to_explicit_spec (tree);
  static int invalid_nontype_parm_type_p (tree, tsubst_flags_t);
  static int eq_local_specializations (const void *, const void *);
  static bool dependent_type_p_r (tree);
- static bool dependent_template_id_p (tree, tree);
  static tree tsubst (tree, tree, tsubst_flags_t, tree);
  static tree tsubst_expr	(tree, tree, tsubst_flags_t, tree);
  static tree tsubst_copy	(tree, tree, tsubst_flags_t, tree);
  
  /* Make the current scope suitable for access checking when we are
--- 165,174 ----
*************** convert_template_argument (tree parm, 
*** 3592,3604 ****
        tree t = tsubst (TREE_TYPE (parm), args, complain, in_decl);
  
        if (invalid_nontype_parm_type_p (t, complain))
          return error_mark_node;
        
-       if (processing_template_decl)
- 	arg = maybe_fold_nontype_arg (arg);
- 
        if (!uses_template_parms (arg) && !uses_template_parms (t))
  	/* We used to call digest_init here.  However, digest_init
  	   will report errors, which we don't want when complain
  	   is zero.  More importantly, digest_init will try too
  	   hard to convert things: for example, `0' should not be
--- 3591,3600 ----
*************** tsubst_baselink (tree baselink, tree obj
*** 7106,7118 ****
      if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
        {
  	template_id_p = true;
  	template_args = TREE_OPERAND (fns, 1);
  	fns = TREE_OPERAND (fns, 0);
! 	template_args = tsubst_copy (template_args, args,
! 				     complain, in_decl);
! 	maybe_fold_nontype_args (template_args);
        }
      name = DECL_NAME (get_first_fn (fns));
      baselink = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
      if (BASELINK_P (baselink) && template_id_p)
        BASELINK_FUNCTIONS (baselink) 
--- 7102,7113 ----
      if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
        {
  	template_id_p = true;
  	template_args = TREE_OPERAND (fns, 1);
  	fns = TREE_OPERAND (fns, 0);
! 	template_args = tsubst_copy_and_build (template_args, args,
! 					       complain, in_decl);
        }
      name = DECL_NAME (get_first_fn (fns));
      baselink = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
      if (BASELINK_P (baselink) && template_id_p)
        BASELINK_FUNCTIONS (baselink) 
*************** tsubst_copy_and_build (tree t, 
*** 8001,8056 ****
  	op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
        return build_x_unary_op (TREE_CODE (t), op1);
  
      case PREDECREMENT_EXPR:
      case PREINCREMENT_EXPR:
-       if (TREE_TYPE (t))
- 	return tsubst_copy (t, args, complain, in_decl);
-       else
- 	return build_x_unary_op
- 	  (TREE_CODE (t),
- 	   tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
- 				  in_decl));
- 
      case NEGATE_EXPR:
      case BIT_NOT_EXPR:
-       if (TREE_TYPE (t))
- 	return tsubst_copy (t, args, complain, in_decl);
-       else
- 	return build_x_unary_op
- 	  (TREE_CODE (t),
- 	   tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
- 				  in_decl));
- 
      case ABS_EXPR:
!       if (TREE_TYPE (t))
! 	return t;
!       return build_x_unary_op
! 	(TREE_CODE (t),
! 	 tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
  
      case ADDR_EXPR:
        op1 = TREE_OPERAND (t, 0);
        if (TREE_CODE (op1) == SCOPE_REF)
  	op1 = tsubst_qualified_id (op1, args, complain, in_decl, 
  				   /*done=*/true, /*address_p=*/true);
        else
  	op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
        return build_x_unary_op (ADDR_EXPR, op1);
  
-     case TRUTH_NOT_EXPR:
-     case CONVERT_EXPR:  /* Unary + */
-     case REALPART_EXPR:
-     case IMAGPART_EXPR:
-       if (TREE_TYPE (t))
- 	return tsubst_copy (t, args, complain, in_decl);
-       else
- 	return build_x_unary_op
- 	  (TREE_CODE (t),
- 	   tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
- 				  in_decl));
- 
      case PLUS_EXPR:
      case MINUS_EXPR:
      case MULT_EXPR:
      case TRUNC_DIV_EXPR:
      case CEIL_DIV_EXPR:
--- 7996,8026 ----
  	op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
        return build_x_unary_op (TREE_CODE (t), op1);
  
      case PREDECREMENT_EXPR:
      case PREINCREMENT_EXPR:
      case NEGATE_EXPR:
      case BIT_NOT_EXPR:
      case ABS_EXPR:
!     case TRUTH_NOT_EXPR:
!     case CONVERT_EXPR:  /* Unary + */
!     case REALPART_EXPR:
!     case IMAGPART_EXPR:
!       return (build_x_unary_op
! 	      (TREE_CODE (t),
! 	       tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
! 				      in_decl)));
  
      case ADDR_EXPR:
        op1 = TREE_OPERAND (t, 0);
        if (TREE_CODE (op1) == SCOPE_REF)
  	op1 = tsubst_qualified_id (op1, args, complain, in_decl, 
  				   /*done=*/true, /*address_p=*/true);
        else
  	op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
        return build_x_unary_op (ADDR_EXPR, op1);
  
      case PLUS_EXPR:
      case MINUS_EXPR:
      case MULT_EXPR:
      case TRUNC_DIV_EXPR:
      case CEIL_DIV_EXPR:
*************** tsubst_copy_and_build (tree t, 
*** 8117,8135 ****
  						     args, complain,
  						     in_decl));
  
      case SIZEOF_EXPR:
      case ALIGNOF_EXPR:
!       {
! 	tree r =
! 	  tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl);
! 	if (!TYPE_P (r))
! 	  return TREE_CODE (t) == SIZEOF_EXPR ?
! 	    expr_sizeof (r) : c_alignof_expr (r);
! 	else
! 	  return cxx_sizeof_or_alignof_type (r, TREE_CODE (t), true);
!       }
  
      case MODOP_EXPR:
        return build_x_modify_expr
  	(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl),
  	 TREE_CODE (TREE_OPERAND (t, 1)),
--- 8087,8115 ----
  						     args, complain,
  						     in_decl));
  
      case SIZEOF_EXPR:
      case ALIGNOF_EXPR:
!       op1 = TREE_OPERAND (t, 0);
!       if (!args)
! 	{
! 	  /* When there are no ARGS, we are trying to evaluate a
! 	     non-dependent expression from the parser.  Trying to do
! 	     the substitutions may not work.  */
! 	  if (!TYPE_P (op1))
! 	    op1 = TREE_TYPE (op1);
! 	}
!       else
! 	{
! 	  ++skip_evaluation;
! 	  op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
! 	  --skip_evaluation;
! 	}
!       if (TREE_CODE (t) == SIZEOF_EXPR)
! 	return finish_sizeof (op1);
!       else
! 	return finish_alignof (op1);
  
      case MODOP_EXPR:
        return build_x_modify_expr
  	(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl),
  	 TREE_CODE (TREE_OPERAND (t, 1)),
*************** tsubst_copy_and_build (tree t, 
*** 8160,8178 ****
  	tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain, in_decl),
  	DELETE_EXPR_USE_VEC (t),
  	DELETE_EXPR_USE_GLOBAL (t));
  
      case COMPOUND_EXPR:
!       {
! 	if (tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl)
! 	    == NULL_TREE)
! 	  return build_x_compound_expr
! 	    (tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
! 				    in_decl));
! 	else
! 	  abort ();
!       }
  
      case CALL_EXPR:
        {
  	tree function;
  	tree call_args;
--- 8140,8154 ----
  	tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain, in_decl),
  	DELETE_EXPR_USE_VEC (t),
  	DELETE_EXPR_USE_GLOBAL (t));
  
      case COMPOUND_EXPR:
!       return (build_x_compound_expr
! 	      (tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, 
! 				      in_decl),
! 	       tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain, 
! 				      in_decl)));
  
      case CALL_EXPR:
        {
  	tree function;
  	tree call_args;
*************** tsubst_copy_and_build (tree t, 
*** 8208,8236 ****
  
  	call_args = tsubst_copy_and_build (TREE_OPERAND (t, 1), args,
  					   complain, in_decl);
  	  
  	if (BASELINK_P (function))
! 	  return build_call_from_tree (function, call_args, 1);
! 	else
! 	  {
! 	    if (call_args != NULL_TREE && koenig_name)
! 	      function = lookup_arg_dependent (koenig_name,
! 					       function, 
! 					       call_args);
! 
! 	    if (TREE_CODE (function) == OFFSET_REF)
! 	      return build_offset_ref_call_from_tree (function, call_args);
! 	    if (TREE_CODE (function) == COMPONENT_REF)
! 	      return (build_new_method_call 
! 		      (TREE_OPERAND (function, 0),
! 		       TREE_OPERAND (function, 1),
! 		       call_args, NULL_TREE, 
! 		       qualified_p ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL));
! 	    return finish_call_expr (function, call_args, 
! 				     /*disallow_virtual=*/qualified_p);
! 	  }
        }
  
      case COND_EXPR:
        return build_x_conditional_expr
  	(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl),
--- 8184,8210 ----
  
  	call_args = tsubst_copy_and_build (TREE_OPERAND (t, 1), args,
  					   complain, in_decl);
  	  
  	if (BASELINK_P (function))
! 	  qualified_p = 1;
! 
! 	if (call_args != NULL_TREE && koenig_name)
! 	  function = lookup_arg_dependent (koenig_name,
! 					   function, 
! 					   call_args);
! 
! 	if (TREE_CODE (function) == OFFSET_REF)
! 	  return build_offset_ref_call_from_tree (function, call_args);
! 	if (TREE_CODE (function) == COMPONENT_REF)
! 	  return (build_new_method_call 
! 		  (TREE_OPERAND (function, 0),
! 		   TREE_OPERAND (function, 1),
! 		   call_args, NULL_TREE, 
! 		   qualified_p ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL));
! 	return finish_call_expr (function, call_args, 
! 				 /*disallow_virtual=*/qualified_p);
        }
  
      case COND_EXPR:
        return build_x_conditional_expr
  	(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl),
*************** tsubst_copy_and_build (tree t, 
*** 8387,8396 ****
--- 8361,8375 ----
        return convert_from_reference (tsubst_copy (t, args, complain, in_decl));
  
      case VAR_DECL:
        if (args)
  	t = tsubst_copy (t, args, complain, in_decl);
+       else
+ 	/* If there are no ARGS, then we are evaluating a
+ 	   non-dependent expression.  If the expression is
+ 	   non-dependent, the variable must be a constant.  */
+ 	t = DECL_INITIAL (t);
        return convert_from_reference (t);
  
      case VA_ARG_EXPR:
  	return build_x_va_arg
  	  (tsubst_copy_and_build
*************** value_dependent_expression_p (tree expre
*** 11489,11518 ****
      return true;
    /* A constant with integral or enumeration type and is initialized 
       with an expression that is value-dependent.  */
    if (TREE_CODE (expression) == VAR_DECL
        && DECL_INITIAL (expression)
!       && INTEGRAL_OR_ENUMERATION_TYPE_P (expression)
        && value_dependent_expression_p (DECL_INITIAL (expression)))
      return true;
    /* These expressions are value-dependent if the type to which the
       cast occurs is dependent or the expression being casted is
       value-dependent.  */
!   if ((TREE_CODE (expression) == DYNAMIC_CAST_EXPR
!        || TREE_CODE (expression) == STATIC_CAST_EXPR
!        || TREE_CODE (expression) == CONST_CAST_EXPR
!        || TREE_CODE (expression) == REINTERPRET_CAST_EXPR
!        || TREE_CODE (expression) == CAST_EXPR)
!       && (dependent_type_p (TREE_TYPE (expression))
!    || value_dependent_expression_p (TREE_OPERAND (expression, 0))))
!     return true;
!   /* A `sizeof' expression where the sizeof operand is a type is
!      value-dependent if the type is dependent.  If the type was not
!      dependent, we would no longer have a SIZEOF_EXPR, so any
!      SIZEOF_EXPR is dependent.  */
!   if (TREE_CODE (expression) == SIZEOF_EXPR)
!     return true;
    /* A constant expression is value-dependent if any subexpression is
       value-dependent.  */
    if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expression))))
      {
        switch (TREE_CODE_CLASS (TREE_CODE (expression)))
--- 11468,11517 ----
      return true;
    /* A constant with integral or enumeration type and is initialized 
       with an expression that is value-dependent.  */
    if (TREE_CODE (expression) == VAR_DECL
        && DECL_INITIAL (expression)
!       && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (expression))
        && value_dependent_expression_p (DECL_INITIAL (expression)))
      return true;
    /* These expressions are value-dependent if the type to which the
       cast occurs is dependent or the expression being casted is
       value-dependent.  */
!   if (TREE_CODE (expression) == DYNAMIC_CAST_EXPR
!       || TREE_CODE (expression) == STATIC_CAST_EXPR
!       || TREE_CODE (expression) == CONST_CAST_EXPR
!       || TREE_CODE (expression) == REINTERPRET_CAST_EXPR
!       || TREE_CODE (expression) == CAST_EXPR)
!     {
!       if (dependent_type_p (TREE_TYPE (expression)))
! 	return true;
!       /* A functional cast has a list of operands.  */
!       expression = TREE_OPERAND (expression, 0);
!       if (TREE_CODE (expression) == TREE_LIST)
! 	{
! 	  do
! 	    {
! 	      if (value_dependent_expression_p (TREE_VALUE (expression)))
! 		return true;
! 	      expression = TREE_CHAIN (expression);
! 	    }
! 	  while (expression);
! 	  return false;
! 	}
!       else
! 	return value_dependent_expression_p (expression);
!     }
!   /* A `sizeof' expression is value-dependent if the operand is
!      type-dependent.  */
!   if (TREE_CODE (expression) == SIZEOF_EXPR
!       || TREE_CODE (expression) == ALIGNOF_EXPR)
!     {
!       expression = TREE_OPERAND (expression, 0);
!       if (TYPE_P (expression))
! 	return dependent_type_p (expression);
!       return type_dependent_expression_p (expression);
!     }
    /* A constant expression is value-dependent if any subexpression is
       value-dependent.  */
    if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expression))))
      {
        switch (TREE_CODE_CLASS (TREE_CODE (expression)))
*************** type_dependent_expression_p (tree expres
*** 11572,11585 ****
        || TREE_CODE (expression) == STATIC_CAST_EXPR
        || TREE_CODE (expression) == CONST_CAST_EXPR
        || TREE_CODE (expression) == REINTERPRET_CAST_EXPR
        || TREE_CODE (expression) == CAST_EXPR)
      return dependent_type_p (TREE_TYPE (expression));
    /* The types of these expressions depends only on the type created
       by the expression.  */
!   else if (TREE_CODE (expression) == NEW_EXPR
! 	   || TREE_CODE (expression) == VEC_NEW_EXPR)
      {
        /* For NEW_EXPR tree nodes created inside a template, either
  	 the object type itself or a TREE_LIST may appear as the
  	 operand 1.  */
        tree type = TREE_OPERAND (expression, 1);
--- 11571,11585 ----
        || TREE_CODE (expression) == STATIC_CAST_EXPR
        || TREE_CODE (expression) == CONST_CAST_EXPR
        || TREE_CODE (expression) == REINTERPRET_CAST_EXPR
        || TREE_CODE (expression) == CAST_EXPR)
      return dependent_type_p (TREE_TYPE (expression));
+ 
    /* The types of these expressions depends only on the type created
       by the expression.  */
!   if (TREE_CODE (expression) == NEW_EXPR
!       || TREE_CODE (expression) == VEC_NEW_EXPR)
      {
        /* For NEW_EXPR tree nodes created inside a template, either
  	 the object type itself or a TREE_LIST may appear as the
  	 operand 1.  */
        tree type = TREE_OPERAND (expression, 1);
*************** type_dependent_expression_p (tree expres
*** 11599,11614 ****
        && (dependent_template_id_p
  	  (DECL_TI_TEMPLATE (expression),
  	   INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))
      return true;
  
    return (dependent_type_p (TREE_TYPE (expression)));
  }
  
! /* Returns TRUE if the ARG (a template argument) is dependent.  */
  
  bool
  dependent_template_arg_p (tree arg)
  {
    if (!processing_template_decl)
      return false;
  
--- 11599,11655 ----
        && (dependent_template_id_p
  	  (DECL_TI_TEMPLATE (expression),
  	   INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))
      return true;
  
+   if (TREE_TYPE (expression) == unknown_type_node)
+     {
+       if (TREE_CODE (expression) == ADDR_EXPR)
+ 	return type_dependent_expression_p (TREE_OPERAND (expression, 0));
+       if (TREE_CODE (expression) == BASELINK)
+ 	expression = BASELINK_FUNCTIONS (expression);
+       if (TREE_CODE (expression) == TEMPLATE_ID_EXPR)
+ 	{
+ 	  if (any_dependent_template_arguments_p (TREE_OPERAND (expression, 
+ 								1)))
+ 	    return true;
+ 	  expression = TREE_OPERAND (expression, 0);
+ 	}
+       if (TREE_CODE (expression) == OVERLOAD)
+ 	{
+ 	  while (expression)
+ 	    {
+ 	      if (type_dependent_expression_p (OVL_CURRENT (expression)))
+ 		return true;
+ 	      expression = OVL_NEXT (expression);
+ 	    }
+ 	  return false;
+ 	}
+       abort ();
+     }
+   
    return (dependent_type_p (TREE_TYPE (expression)));
  }
  
! /* Returns TRUE if ARGS (a TREE_LIST of arguments to a function call)
!    contains a type-dependent expression.  */
  
  bool
+ any_type_dependent_arguments_p (tree args)
+ {
+   while (args)
+     {
+       if (type_dependent_expression_p (TREE_VALUE (args)))
+ 	return true;
+       args = TREE_CHAIN (args);
+     }
+   return false;
+ }
+ 
+ /* Returns TRUE if the ARG (a template argument) is dependent.  */
+ 
+ static bool
  dependent_template_arg_p (tree arg)
  {
    if (!processing_template_decl)
      return false;
  
*************** dependent_template_arg_p (tree arg)
*** 11620,11641 ****
    else
      return (type_dependent_expression_p (arg)
  	    || value_dependent_expression_p (arg));
  }
  
! /* Returns TRUE if the specialization TMPL<ARGS> is dependent.  */
  
! static bool
! dependent_template_id_p (tree tmpl, tree args)
  {
!   int i;
  
-   if (dependent_template_p (tmpl))
-     return true;
-   for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
-     if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
-       return true;
    return false;
  }
  
  /* Returns TRUE if the template TMPL is dependent.  */
  
--- 11661,11700 ----
    else
      return (type_dependent_expression_p (arg)
  	    || value_dependent_expression_p (arg));
  }
  
! /* Returns true if ARGS (a collection of template arguments) contains
!    any dependent arguments.  */
  
! bool
! any_dependent_template_arguments_p (tree args)
  {
!   if (!args)
!     return false;
! 
!   my_friendly_assert (TREE_CODE (args) == TREE_LIST
! 		      || TREE_CODE (args) == TREE_VEC,
! 		      20030707);
! 
!   if (TREE_CODE (args) == TREE_LIST)
!     {
!       while (args)
! 	{
! 	  if (dependent_template_arg_p (TREE_VALUE (args)))
! 	    return true;
! 	  args = TREE_CHAIN (args);
! 	}
!     }
!   else
!     {
!       int i; 
!       for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
! 	if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
! 	  return true;
!     }
  
    return false;
  }
  
  /* Returns TRUE if the template TMPL is dependent.  */
  
*************** dependent_template_p (tree tmpl)
*** 11644,11659 ****
--- 11703,11730 ----
  {
    /* Template template parameters are dependent.  */
    if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)
        || TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)
      return true;
+   /* So are qualified names that have not been looked up.  */
+   if (TREE_CODE (tmpl) == SCOPE_REF)
+     return true;
    /* So are member templates of dependent classes.  */
    if (TYPE_P (CP_DECL_CONTEXT (tmpl)))
      return dependent_type_p (DECL_CONTEXT (tmpl));
    return false;
  }
  
+ /* Returns TRUE if the specialization TMPL<ARGS> is dependent.  */
+ 
+ bool
+ dependent_template_id_p (tree tmpl, tree args)
+ {
+   return (dependent_template_p (tmpl)
+ 	  || any_dependent_template_arguments_p (args));
+ }
+ 
  /* TYPE is a TYPENAME_TYPE.  Returns the ordinary TYPE to which the
     TYPENAME_TYPE corresponds.  Returns ERROR_MARK_NODE if no such TYPE
     can be found.  Note that this function peers inside uninstantiated
     templates and therefore should be used only in extremely limited
     situations.  */
*************** resolve_typename_type (tree type, bool o
*** 11726,11733 ****
--- 11797,11854 ----
      type = cp_build_qualified_type (type, quals);
    /* Leave the SCOPE.  */
    pop_scope (scope);
  
    return type;
+ }
+ 
+ /* EXPR is an expression which is not type-dependent.  Return a proxy
+    for EXPR that can be used to compute the types of larger
+    expressions containing EXPR.  */
+ 
+ tree
+ build_non_dependent_expr (tree expr)
+ {
+   /* Preserve null pointer constants so that the type of things like 
+      "p == 0" where "p" is a pointer can be determined.  */
+   if (null_ptr_cst_p (expr))
+     return expr;
+   /* Preserve OVERLOADs; the functions must be available to resolve
+      types.  */
+   if (TREE_CODE (expr) == OVERLOAD)
+     return expr;
+   /* Otherwise, build a NON_DEPENDENT_EXPR.  
+ 
+      REFERENCE_TYPEs are not stripped for expressions in templates
+      because doing so would play havoc with mangling.  Consider, for
+      example:
+ 
+        template <typename T> void f<T& g>() { g(); } 
+ 
+      In the body of "f", the expression for "g" will have
+      REFERENCE_TYPE, even though the standard says that it should
+      not.  The reason is that we must preserve the syntactic form of
+      the expression so that mangling (say) "f<g>" inside the body of
+      "f" works out correctly.  Therefore, the REFERENCE_TYPE is
+      stripped here.  */
+   return build (NON_DEPENDENT_EXPR, non_reference (TREE_TYPE (expr)));
+ }
+ 
+ /* ARGS is a TREE_LIST of expressions as arguments to a function call.
+    Return a new TREE_LIST with the various arguments replaced with
+    equivalent non-dependent expressions.  */
+ 
+ tree
+ build_non_dependent_args (tree args)
+ {
+   tree a;
+   tree new_args;
+ 
+   new_args = NULL_TREE;
+   for (a = args; a; a = TREE_CHAIN (a))
+     new_args = tree_cons (NULL_TREE, 
+ 			  build_non_dependent_expr (TREE_VALUE (a)),
+ 			  new_args);
+   return nreverse (new_args);
  }
  
  #include "gt-cp-pt.h"
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.324
diff -c -5 -p -r1.324 semantics.c
*** cp/semantics.c	8 Jul 2003 01:38:44 -0000	1.324
--- cp/semantics.c	9 Jul 2003 08:30:24 -0000
*************** tree 
*** 1447,1458 ****
  finish_stmt_expr (tree rtl_expr)
  {
    tree result;
  
    /* If the last thing in the statement-expression was not an
!      expression-statement, then it has type `void'.  */
!   if (!last_expr_type)
      last_expr_type = void_type_node;
    result = build_min (STMT_EXPR, last_expr_type, last_tree);
    TREE_SIDE_EFFECTS (result) = 1;
    
    /* Remove the compound statement from the tree structure; it is
--- 1447,1462 ----
  finish_stmt_expr (tree rtl_expr)
  {
    tree result;
  
    /* If the last thing in the statement-expression was not an
!      expression-statement, then it has type `void'.  In a template, we
!      cannot distinguish the case where the last expression-statement
!      had a dependent type from the case where the last statement was
!      not an expression-statement.  Therefore, we (incorrectly) treat
!      the STMT_EXPR as dependent in that case.  */
!   if (!last_expr_type && !processing_template_decl)
      last_expr_type = void_type_node;
    result = build_min (STMT_EXPR, last_expr_type, last_tree);
    TREE_SIDE_EFFECTS (result) = 1;
    
    /* Remove the compound statement from the tree structure; it is
*************** finish_stmt_expr (tree rtl_expr)
*** 1480,1499 ****
     Returns code for the call.  */
  
  tree 
  finish_call_expr (tree fn, tree args, bool disallow_virtual)
  {
    if (fn == error_mark_node || args == error_mark_node)
      return error_mark_node;
  
-   if (processing_template_decl)
-     return build_nt (CALL_EXPR, fn, args, NULL_TREE);
- 
    /* ARGS should be a list of arguments.  */
    my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST,
  		      20020712);
  
    /* A reference to a member function will appear as an overloaded
       function (rather than a BASELINK) if an unqualified name was used
       to refer to it.  */
    if (!BASELINK_P (fn) && is_overloaded_fn (fn))
      {
--- 1484,1519 ----
     Returns code for the call.  */
  
  tree 
  finish_call_expr (tree fn, tree args, bool disallow_virtual)
  {
+   tree result;
+   tree orig_fn;
+   tree orig_args;
+ 
    if (fn == error_mark_node || args == error_mark_node)
      return error_mark_node;
  
    /* ARGS should be a list of arguments.  */
    my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST,
  		      20020712);
  
+   orig_fn = fn;
+   orig_args = args;
+ 
+   if (processing_template_decl)
+     {
+       if (type_dependent_expression_p (fn)
+ 	  || any_type_dependent_arguments_p (args))
+ 	return build_nt (CALL_EXPR, fn, args);
+       if (!BASELINK_P (fn)
+ 	  && TREE_CODE (fn) != PSEUDO_DTOR_EXPR
+ 	  && TREE_TYPE (fn) != unknown_type_node)
+ 	fn = build_non_dependent_expr (fn);
+       args = build_non_dependent_args (orig_args);
+     }
+ 
    /* A reference to a member function will appear as an overloaded
       function (rather than a BASELINK) if an unqualified name was used
       to refer to it.  */
    if (!BASELINK_P (fn) && is_overloaded_fn (fn))
      {
*************** finish_call_expr (tree fn, tree args, bo
*** 1510,1519 ****
--- 1530,1540 ----
  			       TYPE_BINFO (type),
  			       fn, /*optype=*/NULL_TREE);
  	}
      }
  
+   result = NULL_TREE;
    if (BASELINK_P (fn))
      {
        tree object;
  
        /* A call to a member function.  From [over.call.func]:
*************** finish_call_expr (tree fn, tree args, bo
*** 1549,1591 ****
  	    representative_fn = TREE_OPERAND (representative_fn, 0);
  	  representative_fn = get_first_fn (representative_fn);
  	  object = build_dummy_object (DECL_CONTEXT (representative_fn));
  	}
  
!       return build_new_method_call (object, fn, args, NULL_TREE,
! 				    (disallow_virtual 
! 				     ? LOOKUP_NONVIRTUAL : 0));
      }
    else if (is_overloaded_fn (fn))
      /* A call to a namespace-scope function.  */
!     return build_new_function_call (fn, args);
    else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
      {
-       tree result;
- 
        if (args)
  	error ("arguments to destructor are not allowed");
        /* Mark the pseudo-destructor call as having side-effects so
  	 that we do not issue warnings about its use.  */
        result = build1 (NOP_EXPR,
  		       void_type_node,
  		       TREE_OPERAND (fn, 0));
        TREE_SIDE_EFFECTS (result) = 1;
-       return result;
      }
    else if (CLASS_TYPE_P (TREE_TYPE (fn)))
!     {
!       /* If the "function" is really an object of class type, it might
! 	 have an overloaded `operator ()'.  */
!       tree result;
!       result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE);
!       if (result)
! 	return result;
!     }
  
!   /* A call where the function is unknown.  */
!   return build_function_call (fn, args);
  }
  
  /* Finish a call to a postfix increment or decrement or EXPR.  (Which
     is indicated by CODE, which should be POSTINCREMENT_EXPR or
     POSTDECREMENT_EXPR.)  */
--- 1570,1615 ----
  	    representative_fn = TREE_OPERAND (representative_fn, 0);
  	  representative_fn = get_first_fn (representative_fn);
  	  object = build_dummy_object (DECL_CONTEXT (representative_fn));
  	}
  
!       if (processing_template_decl)
! 	{
! 	  if (type_dependent_expression_p (object))
! 	    return build_nt (CALL_EXPR, orig_fn, orig_args);
! 	  object = build_non_dependent_expr (object);
! 	}
! 
!       result = build_new_method_call (object, fn, args, NULL_TREE,
! 				      (disallow_virtual 
! 				       ? LOOKUP_NONVIRTUAL : 0));
      }
    else if (is_overloaded_fn (fn))
      /* A call to a namespace-scope function.  */
!     result = build_new_function_call (fn, args);
    else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
      {
        if (args)
  	error ("arguments to destructor are not allowed");
        /* Mark the pseudo-destructor call as having side-effects so
  	 that we do not issue warnings about its use.  */
        result = build1 (NOP_EXPR,
  		       void_type_node,
  		       TREE_OPERAND (fn, 0));
        TREE_SIDE_EFFECTS (result) = 1;
      }
    else if (CLASS_TYPE_P (TREE_TYPE (fn)))
!     /* If the "function" is really an object of class type, it might
!        have an overloaded `operator ()'.  */
!     result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE);
!   if (!result)
!     /* A call where the function is unknown.  */
!     result = build_function_call (fn, args);
  
!   if (processing_template_decl)
!     return build (CALL_EXPR, TREE_TYPE (result), orig_fn, orig_args);
!   return result;
  }
  
  /* Finish a call to a postfix increment or decrement or EXPR.  (Which
     is indicated by CODE, which should be POSTINCREMENT_EXPR or
     POSTDECREMENT_EXPR.)  */
Index: cp/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.334
diff -c -5 -p -r1.334 tree.c
*** cp/tree.c	5 Jul 2003 03:02:04 -0000	1.334
--- cp/tree.c	9 Jul 2003 08:30:24 -0000
*************** lvalue_p_1 (tree ref, 
*** 172,181 ****
--- 172,189 ----
        /* All functions (except non-static-member functions) are
  	 lvalues.  */
        return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref) 
  	      ? clk_none : clk_ordinary);
  
+     case NON_DEPENDENT_EXPR:
+       /* We must consider NON_DEPENDENT_EXPRs to be lvalues so that
+ 	 things like "&E" where "E" is an expression with a
+ 	 non-dependent type work. It is safe to be lenient because an
+ 	 error will be issued when the template is instantiated if "E"
+ 	 is not an lvalue.  */
+       return clk_ordinary;
+ 
      default:
        break;
      }
  
    /* If one operand is not an lvalue at all, then this expression is
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.476
diff -c -5 -p -r1.476 typeck.c
*** cp/typeck.c	8 Jul 2003 01:38:44 -0000	1.476
--- cp/typeck.c	9 Jul 2003 08:30:24 -0000
*************** cxx_sizeof_or_alignof_type (tree type, e
*** 1415,1425 ****
    tree value;
    const char *op_name;
  
    my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720);
    if (processing_template_decl)
!     return build_min_nt (op, type);
    
    op_name = operator_name_info[(int) op].name;
  
    type = non_reference (type);
    type_code = TREE_CODE (type);
--- 1415,1425 ----
    tree value;
    const char *op_name;
  
    my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720);
    if (processing_template_decl)
!     return build_min (op, size_type_node, type);
    
    op_name = operator_name_info[(int) op].name;
  
    type = non_reference (type);
    type_code = TREE_CODE (type);
*************** cxx_sizeof_or_alignof_type (tree type, e
*** 1444,1454 ****
  
  tree
  expr_sizeof (tree e)
  {
    if (processing_template_decl)
!     return build_min_nt (SIZEOF_EXPR, e);
  
    if (TREE_CODE (e) == COMPONENT_REF
        && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
      error ("sizeof applied to a bit-field");
    if (is_overloaded_fn (e))
--- 1444,1454 ----
  
  tree
  expr_sizeof (tree e)
  {
    if (processing_template_decl)
!     return build_min (SIZEOF_EXPR, size_type_node, e);
  
    if (TREE_CODE (e) == COMPONENT_REF
        && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
      error ("sizeof applied to a bit-field");
    if (is_overloaded_fn (e))
*************** lookup_destructor (tree object, tree sco
*** 2013,2033 ****
     BASELINK.  */
  
  tree
  finish_class_member_access_expr (tree object, tree name)
  {
    tree object_type;
    tree member;
    tree access_path = NULL_TREE;
  
    if (object == error_mark_node || name == error_mark_node)
      return error_mark_node;
  
    if (processing_template_decl)
!     return build_min_nt (COMPONENT_REF, object, name);
    
-   object_type = TREE_TYPE (object);
    if (TREE_CODE (object_type) == REFERENCE_TYPE)
      {
        object = convert_from_reference (object);
        object_type = TREE_TYPE (object);
      }
--- 2013,2052 ----
     BASELINK.  */
  
  tree
  finish_class_member_access_expr (tree object, tree name)
  {
+   tree expr;
    tree object_type;
    tree member;
    tree access_path = NULL_TREE;
+   tree orig_object = object;
+   tree orig_name = name;
  
    if (object == error_mark_node || name == error_mark_node)
      return error_mark_node;
  
+   object_type = TREE_TYPE (object);
+ 
    if (processing_template_decl)
!     {
!       if (/* If OBJECT_TYPE is dependent, so is OBJECT.NAME.  */
! 	  dependent_type_p (object_type)
! 	  /* If NAME is "f<args>", where either 'f' or 'args' is
! 	     dependent, then the expression is dependent.  */
! 	  || (TREE_CODE (name) == TEMPLATE_ID_EXPR
! 	      && dependent_template_id_p (TREE_OPERAND (name, 0),
! 					  TREE_OPERAND (name, 1)))
! 	  /* If NAME is "T::X" where "T" is dependent, then the
! 	     expression is dependent.  */
! 	  || (TREE_CODE (name) == SCOPE_REF
! 	      && TYPE_P (TREE_OPERAND (name, 0))
! 	      && dependent_type_p (TREE_OPERAND (name, 0))))
! 	return build_min_nt (COMPONENT_REF, object, name);
!       object = build_non_dependent_expr (object);
!     }
    
    if (TREE_CODE (object_type) == REFERENCE_TYPE)
      {
        object = convert_from_reference (object);
        object_type = TREE_TYPE (object);
      }
*************** finish_class_member_access_expr (tree ob
*** 2055,2076 ****
      }
    else
      {
        bool is_template_id = false;
        tree template_args = NULL_TREE;
  
        if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
  	{
  	  is_template_id = true;
  	  template_args = TREE_OPERAND (name, 1);
  	  name = TREE_OPERAND (name, 0);
  	}
  
        if (TREE_CODE (name) == SCOPE_REF)
  	{
- 	  tree scope;
- 
  	  /* A qualified name.  The qualifying class or namespace `S' has
  	     already been looked up; it is either a TYPE or a
  	     NAMESPACE_DECL.  The member name is either an IDENTIFIER_NODE
  	     or a BIT_NOT_EXPR.  */
  	  scope = TREE_OPERAND (name, 0);
--- 2074,2094 ----
      }
    else
      {
        bool is_template_id = false;
        tree template_args = NULL_TREE;
+       tree scope;
  
        if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
  	{
  	  is_template_id = true;
  	  template_args = TREE_OPERAND (name, 1);
  	  name = TREE_OPERAND (name, 0);
  	}
  
        if (TREE_CODE (name) == SCOPE_REF)
  	{
  	  /* A qualified name.  The qualifying class or namespace `S' has
  	     already been looked up; it is either a TYPE or a
  	     NAMESPACE_DECL.  The member name is either an IDENTIFIER_NODE
  	     or a BIT_NOT_EXPR.  */
  	  scope = TREE_OPERAND (name, 0);
*************** finish_class_member_access_expr (tree ob
*** 2093,2153 ****
  
  	  /* Find the base of OBJECT_TYPE corresponding to SCOPE.  */
  	  access_path = lookup_base (object_type, scope, ba_check, NULL);
  	  if (!access_path || access_path == error_mark_node)
  	    return error_mark_node;
- 
- 	  if (TREE_CODE (name) == BIT_NOT_EXPR)
- 	    member = lookup_destructor (object, scope, name);
- 	  else
- 	    {
- 	      /* Look up the member.  */
- 	      member = lookup_member (access_path, name, /*protect=*/1, 
- 				      /*want_type=*/false);
- 	      if (member == NULL_TREE)
- 		{
- 		  error ("'%D' has no member named '%E'", object_type, name);
- 		  return error_mark_node;
- 		}
- 	      if (member == error_mark_node)
- 		return error_mark_node;
- 	    }
  	}
!       else if (TREE_CODE (name) == BIT_NOT_EXPR)
! 	member = lookup_destructor (object, /*scope=*/NULL_TREE, name);
!       else if (TREE_CODE (name) == IDENTIFIER_NODE)
  	{
! 	  /* An unqualified name.  */
! 	  member = lookup_member (object_type, name, /*protect=*/1, 
  				  /*want_type=*/false);
  	  if (member == NULL_TREE)
  	    {
  	      error ("'%D' has no member named '%E'", object_type, name);
  	      return error_mark_node;
  	    }
! 	  else if (member == error_mark_node)
  	    return error_mark_node;
  	}
-       else
- 	{
- 	  /* The YACC parser sometimes gives us things that are not names.
- 	     These always indicate errors.  The recursive-descent parser
- 	     does not do this, so this code can go away once that parser
- 	     replaces the YACC parser.  */
- 	  error ("invalid use of `%D'", name);
- 	  return error_mark_node;
- 	}
        
        if (is_template_id)
  	{
  	  tree template = member;
  	  
  	  if (BASELINK_P (template))
! 	    BASELINK_FUNCTIONS (template) 
! 	      = build_nt (TEMPLATE_ID_EXPR,
! 			  BASELINK_FUNCTIONS (template),
! 			  template_args);
  	  else
  	    {
  	      error ("`%D' is not a member template function", name);
  	      return error_mark_node;
  	    }
--- 2111,2149 ----
  
  	  /* Find the base of OBJECT_TYPE corresponding to SCOPE.  */
  	  access_path = lookup_base (object_type, scope, ba_check, NULL);
  	  if (!access_path || access_path == error_mark_node)
  	    return error_mark_node;
  	}
!       else
! 	{
! 	  scope = NULL_TREE;
! 	  access_path = object_type;
! 	}
! 
!       if (TREE_CODE (name) == BIT_NOT_EXPR)
! 	member = lookup_destructor (object, scope, name);
!       else
  	{
! 	  /* Look up the member.  */
! 	  member = lookup_member (access_path, name, /*protect=*/1, 
  				  /*want_type=*/false);
  	  if (member == NULL_TREE)
  	    {
  	      error ("'%D' has no member named '%E'", object_type, name);
  	      return error_mark_node;
  	    }
! 	  if (member == error_mark_node)
  	    return error_mark_node;
  	}
        
        if (is_template_id)
  	{
  	  tree template = member;
  	  
  	  if (BASELINK_P (template))
! 	    template = lookup_template_function (template, template_args);
  	  else
  	    {
  	      error ("`%D' is not a member template function", name);
  	      return error_mark_node;
  	    }
*************** finish_class_member_access_expr (tree ob
*** 2155,2166 ****
      }
  
    if (TREE_DEPRECATED (member))
      warn_deprecated_use (member);
  
!   return build_class_member_access_expr (object, member, access_path,
  					 /*preserve_reference=*/false);
  }
  
  /* Return an expression for the MEMBER_NAME field in the internal
     representation of PTRMEM, a pointer-to-member function.  (Each
     pointer-to-member function type gets its own RECORD_TYPE so it is
--- 2151,2166 ----
      }
  
    if (TREE_DEPRECATED (member))
      warn_deprecated_use (member);
  
!   expr = build_class_member_access_expr (object, member, access_path,
  					 /*preserve_reference=*/false);
+   if (processing_template_decl && expr != error_mark_node)
+     return build_min (COMPONENT_REF, TREE_TYPE (expr), orig_object, 
+ 		      orig_name);
+   return expr;
  }
  
  /* Return an expression for the MEMBER_NAME field in the internal
     representation of PTRMEM, a pointer-to-member function.  (Each
     pointer-to-member function type gets its own RECORD_TYPE so it is
*************** build_ptrmemfunc_access_expr (tree ptrme
*** 2194,2215 ****
  
     This function may need to overload OPERATOR_FNNAME.
     Must also handle REFERENCE_TYPEs for C++.  */
  
  tree
! build_x_indirect_ref (tree ptr, const char *errorstring)
  {
    tree rval;
  
    if (processing_template_decl)
!     return build_min_nt (INDIRECT_REF, ptr);
  
!   rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE,
  		       NULL_TREE);
!   if (rval)
      return rval;
-   return build_indirect_ref (ptr, errorstring);
  }
  
  tree
  build_indirect_ref (tree ptr, const char *errorstring)
  {
--- 2194,2224 ----
  
     This function may need to overload OPERATOR_FNNAME.
     Must also handle REFERENCE_TYPEs for C++.  */
  
  tree
! build_x_indirect_ref (tree expr, const char *errorstring)
  {
+   tree orig_expr = expr;
    tree rval;
  
    if (processing_template_decl)
!     {
!       if (type_dependent_expression_p (expr))
! 	return build_min_nt (INDIRECT_REF, expr);
!       expr = build_non_dependent_expr (expr);
!     }
  
!   rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
  		       NULL_TREE);
!   if (!rval)
!     rval = build_indirect_ref (expr, errorstring);
! 
!   if (processing_template_decl && rval != error_mark_node)
!     return build_min (INDIRECT_REF, TREE_TYPE (rval), orig_expr);
!   else
      return rval;
  }
  
  tree
  build_indirect_ref (tree ptr, const char *errorstring)
  {
*************** convert_arguments (tree typelist, tree v
*** 2824,3019 ****
     conversions on the operands.  CODE is the kind of expression to build.  */
  
  tree
  build_x_binary_op (enum tree_code code, tree arg1, tree arg2)
  {
!   if (processing_template_decl)
!     return build_min_nt (code, arg1, arg2);
! 
!   if (code == DOTSTAR_EXPR)
!     return build_m_component_ref (arg1, arg2);
! 
!   return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
! }
  
! #if 0
! 
! tree
! build_template_expr (enum tree_code code, tree op0, tree op1, tree op2)
! {
!   tree type;
  
!   /* If any of the operands is erroneous the result is erroneous too.  */
!   if (error_operand_p (op0)
!       || (op1 && error_operand_p (op1))
!       || (op2 && error_operand_p (op2)))
!     return error_mark_node;
!       
!   if (dependent_type_p (TREE_TYPE (op0))
!       || (op1 && dependent_type_p (TREE_TYPE (op1)))
!       || (op2 && dependent_type_p (TREE_TYPE (op2))))
!     /* If at least one operand has a dependent type, we cannot
!        determine the type of the expression until instantiation time.  */
!     type = NULL_TREE;
!   else
      {
!       struct z_candidate *cand;
!       tree op0_type;
!       tree op1_type;
!       tree op2_type;
! 
!       /* None of the operands is dependent, so we can compute the type
! 	 of the expression at this point.  We must compute the type so
! 	 that in things like:
! 
! 	   template <int I>
! 	   void f() { S<sizeof(I + 3)> s; ... }
! 
! 	 we can tell that the type of "s" is non-dependent.
! 
! 	 If we're processing a template argument, we do not want to
! 	 actually change the operands in any way.  Adding conversions,
! 	 performing constant folding, etc., would all change mangled
! 	 names.  For example, in:
! 	 
! 	   template <int I>
! 	   void f(S<sizeof(3 + 4 + I)>);
! 	 
! 	 we need to determine that "3 + 4 + I" has type "int", without
! 	 actually turning the expression into "7 + I".  */
!       cand = find_overloaded_op (code, op0, op1, op2);
!       if (cand) 
! 	/* If an overloaded operator was found, the expression will
! 	   have the type returned by the function.  */
! 	type = non_reference (TREE_TYPE (cand->fn));
!       else
! 	{
! 	  /* There is no overloaded operator so we can just use the
! 	     default rules for determining the type of the operand.  */
! 	  op0_type = TREE_TYPE (op0);
! 	  op1_type = op1 ? TREE_TYPE (op1) : NULL_TREE;
! 	  op2_type = op2 ? TREE_TYPE (op2) : NULL_TREE;
! 	  type = NULL_TREE;
! 
! 	  switch (code)
! 	    {
! 	    case MODIFY_EXPR:
! 	      /* [expr.ass]
! 
! 		 The result of the assignment operation is the value
! 		 stored in the left operand.  */
! 	      type = op0_type;
! 	      break;
! 	    case COMPONENT_REF:
! 	      /* Implement this case.  */
! 	      break;
! 	    case POSTINCREMENT_EXPR:
! 	    case POSTDECREMENT_EXPR:
! 	      /* [expr.post.incr]
! 
! 		 The type of the result is the cv-unqualified version
! 		 of the type of the operand.  */
! 	      type = TYPE_MAIN_VARIANT (op0_type);
! 	      break;
! 	    case PREINCREMENT_EXPR:
! 	    case PREDECREMENT_EXPR:
! 	      /* [expr.pre.incr]
! 
! 		 The value is the new value of the operand.  */
! 	      type = op0_type;
! 	      break;
! 	    case INDIRECT_REF:
! 	      /* [expr.unary.op]
! 
! 		 If the type of the expression is "pointer to T", the
! 		 type of the result is "T".  */
! 	      type = TREE_TYPE (op0_type);
! 	      break;
! 	    case ADDR_EXPR:
! 	      /* [expr.unary.op]
! 
! 		 If the type of the expression is "T", the type of the
! 		 result is "pointer to T".  */
! 	      /* FIXME: Handle the pointer-to-member case.  */
! 	      break;
! 	    case MEMBER_REF:
! 	      /* FIXME: Implement this case.  */
! 	      break;
! 	    case LSHIFT_EXPR:
! 	    case RSHIFT_EXPR:
! 	      /* [expr.shift]
! 
! 		 The type of the result is that of the promoted left
! 		 operand.  */
! 	      break;
! 	    case PLUS_EXPR:
! 	    case MINUS_EXPR:
! 	      /* FIXME: Be careful of special pointer-arithmetic
! 		 cases.  */
! 	      /* Fall through.  */
! 	    case MAX_EXPR:
! 	    case MIN_EXPR:
! 	      /* These are GNU extensions; the result type is computed
! 		 as it would be for other arithmetic operators.  */
! 	      /* Fall through.  */
! 	    case BIT_AND_EXPR:
! 	    case BIT_XOR_EXPR:
! 	    case BIT_IOR_EXPR:
! 	    case MULT_EXPR:
! 	    case TRUNC_DIV_EXPR:
! 	    case TRUNC_MOD_EXPR:
! 	      /* [expr.bit.and], [expr.xor], [expr.or], [expr.mul]
! 
! 		 The usual arithmetic conversions are performed on the
! 		 operands and determine the type of the result.  */
! 	      /* FIXME: Check that this is possible.  */
! 	      type = type_after_usual_arithmetic_conversions (t1, t2);
! 	      break;
! 	    case GT_EXPR:
! 	    case LT_EXPR:
! 	    case GE_EXPR:
! 	    case LE_EXPR:
! 	    case EQ_EXPR:
! 	    case NE_EXPR:
! 	      /* [expr.rel]
! 
! 		 The type of the result is bool.  */
! 	      type = boolean_type_node;
! 	      break;
! 	    case TRUTH_ANDIF_EXPR:
! 	    case TRUTH_ORIF_EXPR:
! 	      /* [expr.log.and], [expr.log.org]
! 		 
! 		 The result is a bool.  */
! 	      type = boolean_type_node;
! 	      break;
! 	    case COND_EXPR:
! 	      /* FIXME: Handle special rules for conditional
! 		 expressions.  */
! 	      break;
! 	    case COMPOUND_EXPR:
! 	      type = op1_type;
! 	      break;
! 	    default:
! 	      abort ();
! 	    }
! 	  /* If the type of the expression could not be determined,
! 	     something is wrong.  */
! 	  if (!type)
! 	    abort ();
! 	  /* If the type is erroneous, the expression is erroneous
! 	     too.  */
! 	  if (type == error_mark_node)
! 	    return error_mark_node;
! 	}
      }
    
!   return build_min (code, type, op0, op1, op2, NULL_TREE);
  }
  
- #endif
- 
  /* Build a binary-operation expression without default conversions.
     CODE is the kind of expression to build.
     This function differs from `build' in several ways:
     the data type of the result is computed and recorded in it,
     warnings are generated if arg data types are invalid,
--- 2833,2869 ----
     conversions on the operands.  CODE is the kind of expression to build.  */
  
  tree
  build_x_binary_op (enum tree_code code, tree arg1, tree arg2)
  {
!   tree orig_arg1;
!   tree orig_arg2;
!   tree expr;
  
!   orig_arg1 = arg1;
!   orig_arg2 = arg2;
  
!   if (processing_template_decl)
      {
!       if (type_dependent_expression_p (arg1)
! 	  || type_dependent_expression_p (arg2))
! 	return build_min_nt (code, arg1, arg2);
!       arg1 = build_non_dependent_expr (arg1);
!       arg2 = build_non_dependent_expr (arg2);
      }
+ 
+   if (code == DOTSTAR_EXPR)
+     expr = build_m_component_ref (arg1, arg2);
+   else
+     expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
+ 
+   if (processing_template_decl && expr != error_mark_node)
+     return build_min (code, TREE_TYPE (expr), orig_arg1, orig_arg2);
    
!   return expr;
  }
  
  /* Build a binary-operation expression without default conversions.
     CODE is the kind of expression to build.
     This function differs from `build' in several ways:
     the data type of the result is computed and recorded in it,
     warnings are generated if arg data types are invalid,
*************** pointer_diff (register tree op0, registe
*** 3837,3870 ****
     and XARG is the operand.  */
  
  tree
  build_x_unary_op (enum tree_code code, tree xarg)
  {
    tree exp;
    int ptrmem = 0;
    
    if (processing_template_decl)
!     return build_min_nt (code, xarg, NULL_TREE);
  
    /* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an
       error message.  */
    if (code == ADDR_EXPR
        && TREE_CODE (xarg) != TEMPLATE_ID_EXPR
        && ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
  	   && !COMPLETE_TYPE_P (TREE_TYPE (xarg)))
  	  || (TREE_CODE (xarg) == OFFSET_REF)))
      /* don't look for a function */;
    else
!     {
!       tree rval;
! 
!       rval = build_new_op (code, LOOKUP_NORMAL, xarg,
! 			   NULL_TREE, NULL_TREE);
!       if (rval || code != ADDR_EXPR)
! 	return rval;
!     }
!   if (code == ADDR_EXPR)
      {
        /*  A pointer to member-function can be formed only by saying
  	  &X::mf.  */
        if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE
  	  && (TREE_CODE (xarg) != OFFSET_REF || !PTRMEM_OK_P (xarg)))
--- 3687,3720 ----
     and XARG is the operand.  */
  
  tree
  build_x_unary_op (enum tree_code code, tree xarg)
  {
+   tree orig_expr = xarg;
    tree exp;
    int ptrmem = 0;
    
    if (processing_template_decl)
!     {
!       if (type_dependent_expression_p (xarg))
! 	return build_min_nt (code, xarg, NULL_TREE);
!       xarg = build_non_dependent_expr (xarg);
!     }
! 
!   exp = NULL_TREE;
  
    /* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an
       error message.  */
    if (code == ADDR_EXPR
        && TREE_CODE (xarg) != TEMPLATE_ID_EXPR
        && ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
  	   && !COMPLETE_TYPE_P (TREE_TYPE (xarg)))
  	  || (TREE_CODE (xarg) == OFFSET_REF)))
      /* don't look for a function */;
    else
!     exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE);
!   if (!exp && code == ADDR_EXPR)
      {
        /*  A pointer to member-function can be formed only by saying
  	  &X::mf.  */
        if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE
  	  && (TREE_CODE (xarg) != OFFSET_REF || !PTRMEM_OK_P (xarg)))
*************** build_x_unary_op (enum tree_code code, t
*** 3894,3913 ****
                   pointer-to-member.  */
  	      xarg = build (OFFSET_REF, TREE_TYPE (xarg),
  			    TREE_OPERAND (xarg, 0),
  			    ovl_cons (TREE_OPERAND (xarg, 1), NULL_TREE));
  	      PTRMEM_OK_P (xarg) = ptrmem;
! 	    }
! 	      
          }
        else if (TREE_CODE (xarg) == TARGET_EXPR)
  	warning ("taking address of temporary");
      }
-   exp = build_unary_op (code, xarg, 0);
-   if (TREE_CODE (exp) == ADDR_EXPR)
-     PTRMEM_OK_P (exp) = ptrmem;
  
    return exp;
  }
  
  /* Like c_common_truthvalue_conversion, but handle pointer-to-member
     constants, where a null value is represented by an INTEGER_CST of
--- 3744,3764 ----
                   pointer-to-member.  */
  	      xarg = build (OFFSET_REF, TREE_TYPE (xarg),
  			    TREE_OPERAND (xarg, 0),
  			    ovl_cons (TREE_OPERAND (xarg, 1), NULL_TREE));
  	      PTRMEM_OK_P (xarg) = ptrmem;
! 	    }	      
          }
        else if (TREE_CODE (xarg) == TARGET_EXPR)
  	warning ("taking address of temporary");
+       exp = build_unary_op (ADDR_EXPR, xarg, 0);
+       if (TREE_CODE (exp) == ADDR_EXPR)
+ 	PTRMEM_OK_P (exp) = ptrmem;
      }
  
+   if (processing_template_decl && exp != error_mark_node)
+     return build_min (code, TREE_TYPE (exp), orig_expr);
    return exp;
  }
  
  /* Like c_common_truthvalue_conversion, but handle pointer-to-member
     constants, where a null value is represented by an INTEGER_CST of
*************** cxx_mark_addressable (tree exp)
*** 4629,4685 ****
  /* Build and return a conditional expression IFEXP ? OP1 : OP2.  */
  
  tree
  build_x_conditional_expr (tree ifexp, tree op1, tree op2)
  {
!   if (processing_template_decl)
!     return build_min_nt (COND_EXPR, ifexp, op1, op2);
  
!   return build_conditional_expr (ifexp, op1, op2);
  }
  
  /* Handle overloading of the ',' operator when needed.  Otherwise,
     this function just builds an expression list.  */
  
  tree
! build_x_compound_expr (tree list)
  {
-   tree rest = TREE_CHAIN (list);
    tree result;
  
    if (processing_template_decl)
!     return build_min_nt (COMPOUND_EXPR, list, NULL_TREE);
! 
!   if (rest == NULL_TREE)
!     return build_compound_expr (list);
! 
!   result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL,
! 			 TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
!   if (result)
!     return build_x_compound_expr (tree_cons (NULL_TREE, result,
! 						  TREE_CHAIN (rest)));
! 
!   if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
!     {
!       /* FIXME: This test should be in the implicit cast to void of the LHS.  */
!       /* the left-hand operand of a comma expression is like an expression
!          statement: we should warn if it doesn't have any side-effects,
!          unless it was explicitly cast to (void).  */
!       if (warn_unused_value
!            && !(TREE_CODE (TREE_VALUE(list)) == CONVERT_EXPR
!                 && VOID_TYPE_P (TREE_TYPE (TREE_VALUE(list)))))
!         warning("left-hand operand of comma expression has no effect");
!     }
! #if 0 /* this requires a gcc backend patch to export warn_if_unused_value */
!   else if (warn_unused_value)
!     warn_if_unused_value (TREE_VALUE(list));
! #endif
! 
!   return build_compound_expr
!     (tree_cons (NULL_TREE, TREE_VALUE (list),
! 		     build_tree_list (NULL_TREE,
! 				      build_x_compound_expr (rest))));
  }
  
  /* Given a list of expressions, return a compound expression
     that performs them all and returns the value of the last of them.  */
  
--- 4480,4559 ----
  /* Build and return a conditional expression IFEXP ? OP1 : OP2.  */
  
  tree
  build_x_conditional_expr (tree ifexp, tree op1, tree op2)
  {
!   tree orig_ifexp = ifexp;
!   tree orig_op1 = op1;
!   tree orig_op2 = op2;
!   tree expr;
  
!   if (processing_template_decl)
!     {
!       /* The standard says that the expression is type-dependent if
! 	 IFEXP is type-dependent, even though the eventual type of the
! 	 expression doesn't dependent on IFEXP.  */
!       if (type_dependent_expression_p (ifexp)
! 	  || type_dependent_expression_p (op1)
! 	  || type_dependent_expression_p (op2))
! 	return build_min_nt (COND_EXPR, ifexp, op1, op2);
!       ifexp = build_non_dependent_expr (ifexp);
!       op1 = build_non_dependent_expr (op1);
!       op2 = build_non_dependent_expr (op2);
!     }
! 
!   expr = build_conditional_expr (ifexp, op1, op2);
!   if (processing_template_decl && expr != error_mark_node)
!     return build_min (COND_EXPR, TREE_TYPE (expr), 
! 		      orig_ifexp, orig_op1, orig_op2);
!   return expr;
  }
  
  /* Handle overloading of the ',' operator when needed.  Otherwise,
     this function just builds an expression list.  */
  
  tree
! build_x_compound_expr (tree op1, tree op2)
  {
    tree result;
+   tree orig_op1 = op1;
+   tree orig_op2 = op2;
  
    if (processing_template_decl)
!     {
!       if (type_dependent_expression_p (op1)
! 	  || type_dependent_expression_p (op2))
! 	return build_min_nt (COMPOUND_EXPR, op1, op2);
!       op1 = build_non_dependent_expr (op1);
!       op2 = build_non_dependent_expr (op2);
!     }
! 
!   result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE);
!   if (!result)
!     {
!       if (! TREE_SIDE_EFFECTS (op1))
! 	{
! 	  /* FIXME: This test should be in the implicit cast to void
! 	     of the LHS.  */
! 	  /* the left-hand operand of a comma expression is like an expression
! 	     statement: we should warn if it doesn't have any side-effects,
! 	     unless it was explicitly cast to (void).  */
! 	  if (warn_unused_value
! 	      && !(TREE_CODE (op1) == CONVERT_EXPR
! 		   && VOID_TYPE_P (TREE_TYPE (op1))))
! 	    warning("left-hand operand of comma expression has no effect");
! 	}
!       result = build_compound_expr (tree_cons (NULL_TREE,
! 					       op1,
! 					       build_tree_list (NULL_TREE,
! 								op2)));
!     }
! 
!   if (processing_template_decl && result != error_mark_node)
!     return build_min (COMPOUND_EXPR, TREE_TYPE (result), 
! 		      orig_op1, orig_op2);
!   return result;
  }
  
  /* Given a list of expressions, return a compound expression
     that performs them all and returns the value of the last of them.  */
  
Index: cp/typeck2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck2.c,v
retrieving revision 1.143
diff -c -5 -p -r1.143 typeck2.c
*** cp/typeck2.c	6 Jul 2003 03:30:56 -0000	1.143
--- cp/typeck2.c	9 Jul 2003 08:30:24 -0000
*************** build_scoped_ref (tree datum, tree baset
*** 978,1025 ****
     performed until an object which does not have the `->' operator
     overloaded is found.  An error is reported when circular pointer
     delegation is detected.  */
  
  tree
! build_x_arrow (tree datum)
  {
    tree types_memoized = NULL_TREE;
!   register tree rval = datum;
!   tree type = TREE_TYPE (rval);
    tree last_rval = NULL_TREE;
  
    if (type == error_mark_node)
      return error_mark_node;
  
    if (processing_template_decl)
!     return build_min_nt (ARROW_EXPR, rval);
  
    if (TREE_CODE (type) == REFERENCE_TYPE)
      {
!       rval = convert_from_reference (rval);
!       type = TREE_TYPE (rval);
      }
  
    if (IS_AGGR_TYPE (type))
      {
!       while ((rval = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, rval,
  				   NULL_TREE, NULL_TREE)))
  	{
! 	  if (rval == error_mark_node)
  	    return error_mark_node;
  
! 	  if (value_member (TREE_TYPE (rval), types_memoized))
  	    {
  	      error ("circular pointer delegation detected");
  	      return error_mark_node;
  	    }
  	  else
  	    {
! 	      types_memoized = tree_cons (NULL_TREE, TREE_TYPE (rval),
  					  types_memoized);
  	    }
! 	  last_rval = rval;
  	}     
  
        if (last_rval == NULL_TREE)
  	{
  	  error ("base operand of `->' has non-pointer type `%T'", type);
--- 978,1029 ----
     performed until an object which does not have the `->' operator
     overloaded is found.  An error is reported when circular pointer
     delegation is detected.  */
  
  tree
! build_x_arrow (tree expr)
  {
+   tree orig_expr = expr;
    tree types_memoized = NULL_TREE;
!   tree type = TREE_TYPE (expr);
    tree last_rval = NULL_TREE;
  
    if (type == error_mark_node)
      return error_mark_node;
  
    if (processing_template_decl)
!     {
!       if (type_dependent_expression_p (expr))
! 	return build_min_nt (ARROW_EXPR, expr);
!       expr = build_non_dependent_expr (expr);
!     }
  
    if (TREE_CODE (type) == REFERENCE_TYPE)
      {
!       expr = convert_from_reference (expr);
!       type = TREE_TYPE (expr);
      }
  
    if (IS_AGGR_TYPE (type))
      {
!       while ((expr = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, expr,
  				   NULL_TREE, NULL_TREE)))
  	{
! 	  if (expr == error_mark_node)
  	    return error_mark_node;
  
! 	  if (value_member (TREE_TYPE (expr), types_memoized))
  	    {
  	      error ("circular pointer delegation detected");
  	      return error_mark_node;
  	    }
  	  else
  	    {
! 	      types_memoized = tree_cons (NULL_TREE, TREE_TYPE (expr),
  					  types_memoized);
  	    }
! 	  last_rval = expr;
  	}     
  
        if (last_rval == NULL_TREE)
  	{
  	  error ("base operand of `->' has non-pointer type `%T'", type);
*************** build_x_arrow (tree datum)
*** 1028,1041 ****
  
        if (TREE_CODE (TREE_TYPE (last_rval)) == REFERENCE_TYPE)
  	last_rval = convert_from_reference (last_rval);
      }
    else
!     last_rval = decay_conversion (rval);
  
    if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE)
!     return build_indirect_ref (last_rval, NULL);
  
    if (types_memoized)
      error ("result of `operator->()' yields non-pointer result");
    else
      error ("base operand of `->' is not a pointer");
--- 1032,1052 ----
  
        if (TREE_CODE (TREE_TYPE (last_rval)) == REFERENCE_TYPE)
  	last_rval = convert_from_reference (last_rval);
      }
    else
!     last_rval = decay_conversion (expr);
  
    if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE)
!     {
!       if (processing_template_decl)
! 	return build_min (ARROW_EXPR, 
! 			  TREE_TYPE (TREE_TYPE (last_rval)), 
! 			  orig_expr);
! 
!       return build_indirect_ref (last_rval, NULL);
!     }
  
    if (types_memoized)
      error ("result of `operator->()' yields non-pointer result");
    else
      error ("base operand of `->' is not a pointer");
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.313
diff -c -5 -p -r1.313 invoke.texi
*** doc/invoke.texi	9 Jul 2003 01:20:24 -0000	1.313
--- doc/invoke.texi	9 Jul 2003 08:30:25 -0000
*************** Dump after running tracer, to @file{@var
*** 3215,3225 ****
  @opindex du
  Dump after null pointer elimination pass to @file{@var{file}.018.null}.
  @item U
  @opindex dU
  Dump callgraph and unit-at-a-time optimization @file{@var{file}.00.unit}.
! @litem w
  @opindex dw
  Dump after the second flow pass, to @file{@var{file}.29.flow2}.
  @item W
  @opindex dW
  Dump after SSA conditional constant propagation, to
--- 3215,3225 ----
  @opindex du
  Dump after null pointer elimination pass to @file{@var{file}.018.null}.
  @item U
  @opindex dU
  Dump callgraph and unit-at-a-time optimization @file{@var{file}.00.unit}.
! @item w
  @opindex dw
  Dump after the second flow pass, to @file{@var{file}.29.flow2}.
  @item W
  @opindex dW
  Dump after SSA conditional constant propagation, to
Index: testsuite/g++.dg/abi/mangle17.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/abi/mangle17.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 mangle17.C
*** testsuite/g++.dg/abi/mangle17.C	17 Oct 2002 02:07:44 -0000	1.1
--- testsuite/g++.dg/abi/mangle17.C	9 Jul 2003 08:30:26 -0000
***************
*** 2,11 ****
  
  enum E { e = 3 };
  
  template <int I> struct S {};
  
! template <int I> void f (S<e + int (3.7)>) {}
! template void f<7>(S<e + int (3.7)>);  // { dg-warning "mangle" }
  
! template <int I> void g (S<e + int (3.7)>) {}
! template void g<7>(S<e + int (3.7)>); // { dg-warning "mangle" }
--- 2,11 ----
  
  enum E { e = 3 };
  
  template <int I> struct S {};
  
! template <int I> void f (S<I + e + int (3.7)>) {}
! template void f<7>(S<7 + e + int (3.7)>);  // { dg-warning "mangle" }
  
! template <int I> void g (S<I + e + int (3.7)>) {}
! template void g<7>(S<7 + e + int (3.7)>); // { dg-warning "mangle" }
Index: testsuite/g++.dg/abi/mangle4.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/abi/mangle4.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 mangle4.C
*** testsuite/g++.dg/abi/mangle4.C	26 Jun 2003 00:07:50 -0000	1.2
--- testsuite/g++.dg/abi/mangle4.C	9 Jul 2003 08:30:26 -0000
*************** class B : public A {};
*** 6,26 ****
  
  template<const A* a> class C {};
  template<const B* b> class D {};
  template<B* b> class E {};
  
! template<const B* b> void f(D<b> &, C<static_cast<const A*>(b)> &) {}
! template<const B* b> void g(D<b> &, E<const_cast<B*>(b)> &) {}
  
  B b;
  
  int main()
  {
!   C<static_cast<const A*>(&b)> c;
    D<&b> d;
!   E<const_cast<B*>(&b)> e;
!   f(d, c);
!   g(d, e);
  }
  
- // { dg-final { scan-assembler "\n_?_Z1fIXadL_Z1bEEEvR1DIXT_EER1CIXcvPK1AT_EE\[: \t\n\]" } }
- // { dg-final { scan-assembler "\n_?_Z1gIXadL_Z1bEEEvR1DIXT_EER1EIXcvP1BT_EE\[: \t\n\]" } }
--- 6,24 ----
  
  template<const A* a> class C {};
  template<const B* b> class D {};
  template<B* b> class E {};
  
! template<const B* b> void f(D<b> &, C<static_cast<const A*>(b)> &) {} // { dg-error "" }
! template<const B* b> void g(D<b> &, E<const_cast<B*>(b)> &) {} // { dg-error "" }
  
  B b;
  
  int main()
  {
!   C<static_cast<const A*>(&b)> c; // { dg-error "" }
    D<&b> d;
!   E<const_cast<B*>(&b)> e; // { dg-error "" }
!   f(d, c); // { dg-error "" }
!   g(d, e); // { dg-error "" }
  }
  
Index: testsuite/g++.dg/debug/debug7.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/debug/debug7.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 debug7.C
*** testsuite/g++.dg/debug/debug7.C	5 Jul 2002 16:40:01 -0000	1.2
--- testsuite/g++.dg/debug/debug7.C	9 Jul 2003 08:30:26 -0000
*************** void f (int);
*** 5,15 ****
  int
  main() {
  
    int a = 4;
    int b = 5;
!   int (*x)[b] = new int[a][b];
  
    x[2][1] = 7;
  
    for (int i = 0; i < a; ++i)
      for (int j = 0; j < b; ++j)
--- 5,15 ----
  int
  main() {
  
    int a = 4;
    int b = 5;
!   int (*x)[b] = new int[a][b]; // { dg-error "" }
  
    x[2][1] = 7;
  
    for (int i = 0; i < a; ++i)
      for (int j = 0; j < b; ++j)
Index: testsuite/g++.dg/opt/stack1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/opt/stack1.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 stack1.C
*** testsuite/g++.dg/opt/stack1.C	7 Jul 2003 07:25:36 -0000	1.1
--- testsuite/g++.dg/opt/stack1.C	9 Jul 2003 08:30:26 -0000
*************** struct matrix {
*** 66,76 ****
  
  template<typename=void>
  struct adaptor {
      adaptor (matrix<> &m) : m(&m), upper_ (1) {}
  
!     int size1 () const     { return m->size1 (); }
      int size2 () const     { return 3; }
      int lower () const     { return 1; }
      int upper () const     { return upper_; }
      matrix<> &data () { return *m; }
  
--- 66,76 ----
  
  template<typename=void>
  struct adaptor {
      adaptor (matrix<> &m) : m(&m), upper_ (1) {}
  
!     int size1 () const;
      int size2 () const     { return 3; }
      int lower () const     { return 1; }
      int upper () const     { return upper_; }
      matrix<> &data () { return *m; }
  
Index: testsuite/g++.dg/parse/template7.C
===================================================================
RCS file: testsuite/g++.dg/parse/template7.C
diff -N testsuite/g++.dg/parse/template7.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/parse/template7.C	9 Jul 2003 08:30:26 -0000
***************
*** 0 ****
--- 1,4 ----
+ template <int I>
+ void f();
+ 
+ void g() { f<(3, 2)>(); } // { dg-error "" }
Index: testsuite/g++.dg/template/dependent-expr1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/template/dependent-expr1.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 dependent-expr1.C
*** testsuite/g++.dg/template/dependent-expr1.C	2 Jul 2003 09:36:20 -0000	1.1
--- testsuite/g++.dg/template/dependent-expr1.C	9 Jul 2003 08:30:26 -0000
*************** namespace std
*** 19,29 ****
      Foo (sizeof (x));
      Foo (__alignof__ (I));
      Foo (__alignof__ (x));
      Foo (x->~I ());
      //    Foo (typeid (I));
!     Foo (delete x);
!     Foo (delete[] x);
!     Foo (throw x);
    }
  
  }
--- 19,29 ----
      Foo (sizeof (x));
      Foo (__alignof__ (I));
      Foo (__alignof__ (x));
      Foo (x->~I ());
      //    Foo (typeid (I));
!     Foo (delete x); // { dg-error "" }
!     Foo (delete[] x); // { dg-error "" }
!     Foo (throw x); // { dg-error "" }
    }
  
  }
Index: testsuite/g++.old-deja/g++.pt/crash41.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.pt/crash41.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 crash41.C
*** testsuite/g++.old-deja/g++.pt/crash41.C	1 May 2003 02:02:53 -0000	1.3
--- testsuite/g++.old-deja/g++.pt/crash41.C	9 Jul 2003 08:30:26 -0000
***************
*** 1,11 ****
! // { dg-do assemble  }
  // Origin: Mark Mitchell <mark@codesourcery.com>
  
  template <int> struct S1{};
  
  struct S2 { int i; };
  
  template <class T>
  void f(S2 s2) {
!   S1<s2.i> s1;
  }
--- 1,11 ----
! // { dg-do compile  }
  // Origin: Mark Mitchell <mark@codesourcery.com>
  
  template <int> struct S1{};
  
  struct S2 { int i; };
  
  template <class T>
  void f(S2 s2) {
!   S1<s2.i> s1; // { dg-error "" }
  }
Index: gcj/array.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gcj/array.h,v
retrieving revision 1.13
diff -c -5 -p -r1.13 array.h
*** gcj/array.h	28 Dec 2002 06:38:52 -0000	1.13
--- gcj/array.h	9 Jul 2003 08:44:56 -0000
*************** typedef JArray<jdouble> *jdoubleArray;
*** 69,79 ****
  typedef JArray<jstring> *jstringArray;
  
  extern java::lang::Class _Jv_byteClass, _Jv_shortClass, _Jv_intClass,
    _Jv_longClass, _Jv_booleanClass, _Jv_charClass, _Jv_floatClass,
    _Jv_doubleClass, _Jv_voidClass;
! #define JvPrimClass(TYPE) (& _Jv_##TYPE##Class)
  
  extern "C" jobjectArray _Jv_NewObjectArray(jsize length, jclass, jobject init);
  extern "C" jobject _Jv_NewPrimArray (jclass eltype, jint count);
  
  extern inline jobjectArray 
--- 69,81 ----
  typedef JArray<jstring> *jstringArray;
  
  extern java::lang::Class _Jv_byteClass, _Jv_shortClass, _Jv_intClass,
    _Jv_longClass, _Jv_booleanClass, _Jv_charClass, _Jv_floatClass,
    _Jv_doubleClass, _Jv_voidClass;
! /* The definition of this macro cannot be enclosed in parentheses
!    because "JvPrimClass(x)" is used as a template argument.  */
! #define JvPrimClass(TYPE) & _Jv_##TYPE##Class
  
  extern "C" jobjectArray _Jv_NewObjectArray(jsize length, jclass, jobject init);
  extern "C" jobject _Jv_NewPrimArray (jclass eltype, jint count);
  
  extern inline jobjectArray 


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