C++ PATCH: PR 11493 and PR 11495

Mark Mitchell mark@codesourcery.com
Mon Jul 14 03:01:00 GMT 2003


This patch fixes PR 11493 and PR 11495, mainline regressions from the
non-dependent expression patch.

After this patch, this kind of thing:

  template <typename T> void f() { g(); }

will no longer compile.  

That's also true in the case of:

 template <typename T> struct B { void f(int); };
 template <typename T> struct D : public B { void g() { f(3); } };

The call to "f" is invalid because there are no dependent arguments,
so "f" is looked up at parse time.  The right way to write the call is
"this->f(3)".

We do still accept the old way of doing things with "-fpermissive",
because that is how most compilers (including G++) used to work.

For this case:

  template <typename T> void f() { g(); }

we say:

  test.C:1: error: there are no arguments to `g' that depend on a template 
     parameter, so a declaration of `g' must be available
  test.C:1: error: (if you use `-fpermissive', G++ will accept your code, but 
     allowing the use of an undeclared name is deprecated)

without -fpermissive, and just:

  test.C:1: warning: there are no arguments to `g' that depend on a template 
     parameter, so a declaration of `g' must be available

when using -fpermissive.

This patch further expands the "new parser dividend" by sharing yet
more code between the parsing and template instantiation phases of the
compiler, and the antiquated "do_identifier" and "do_scoped_id"
functions are no more.

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

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

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

	* cp-tree.h (cp_id_kind): New type.
	(unqualified_name_lookup_error): Change prototype.
	(unqualified_fn_lookup_error): New function.
	(do_identifier): Remove.
	(do_scoped_id): Likewise.
	(tsubst_copy_and_build): Change prototype.
	(reregister_specialization): New function.
	(perform_koenig_lookup): Likewise.
	(finish_id_expression): Likewise.
	* call.c (build_method_call): Adjust call to
	unqualified_name_lookup_error.
	* decl.c (duplicate_decls): Use reregister_specialization.
	* lex.c (is_global): Remove.
	(unqualified_name_lookup_error): Return a value.
	(do_identifier): Remove.
	(do_scoped_id): Likewise.
	(identifier_typedecl_value): Remove.
	(unqualified_fn_lookup_error): New function.
	* parser.c (cp_parser_id_kind): Remove.
	(cp_parser_non_constant_id_expression): Remove.
	(cp_parser_primary_expression): Use finish_id_expression.
	(cp_parser_class_or_namespace_name): Use cp_id_kind, not
	cp_parser_id_kind.
	(cp_parser_postfix_expression): Use perform_koenig_lookup.
	(cp_parser_template_argument): Use cp_id_kind.
	(cp_parser_fold_non_dependent_expr): Adjust call to
	tsubst_copy_and_build.
	* pt.c (unregister_specialization): Rename to ...
	(reregister_specialization): This.
	(tsubst_friend_function): Use it.
	(maybe_fold_nontype_arg): Adjust call to tsubst_copy_and_build.
	(tsubst_qualified_id): Likewise.
	(tsubst_expr): Likewise.
	(tsubst_copy_and_build): Add function_p parameter.  Use
	finish_id_expression.  Introduce RECUR macro.
	(tsubst_non_call_postfix_expression): New function.
	(regenerate_decl_from_template): Use reregister_specialization.
	* semantics.c (perform_koenig_lookup): New function.
	(finish_id_expression): Likewise.

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

	PR c++/11493
	PR c++/11495
	* g++.dg/parse/template9.C: Likewise.
	* g++.dg/template/crash4.C: New test.
	* g++.dg/template/koenig1.C: Likewise.
	* g++.old-deja/g++.benjamin/tem03.C: Adjust error markers.
	* g++.old-deja/g++.benjamin/tem06.C: Declare "x".
	* g++.old-deja/g++.jason/overload33.C: Use this-> when calling
	functions.
	* g++.old-deja/g++.jason/template36.C: Likewise.
	* g++.old-deja/g++.mike/p1989.C: Likewise.
	* g++.old-deja/g++.pt/lookup2.C: Use -fpermissive when compiling.
	* g++.old-deja/g++.pt/ttp20.C: Use this->.
	* g++.old-deja/g++.pt/ttp21.C: Use this->.
	* g++.old-deja/g++.pt/typename13.C: Use -fpermissive when
	compiling.
	* g++.old-deja/g++.pt/union2.C: Use this->.

Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.404
diff -c -5 -p -r1.404 call.c
*** cp/call.c	9 Jul 2003 08:47:58 -0000	1.404
--- cp/call.c	14 Jul 2003 02:30:48 -0000
*************** build_method_call (tree instance, tree n
*** 421,434 ****
        return error_mark_node;
      }
  
    /* If the name could not be found, issue an error.  */
    if (!fn)
!     {
!       unqualified_name_lookup_error (name);
!       return error_mark_node;
!     }
  
    if (BASELINK_P (fn) && has_template_args)
      BASELINK_FUNCTIONS (fn)
        = build_nt (TEMPLATE_ID_EXPR,
  		  BASELINK_FUNCTIONS (fn),
--- 421,431 ----
        return error_mark_node;
      }
  
    /* If the name could not be found, issue an error.  */
    if (!fn)
!     return unqualified_name_lookup_error (name);
  
    if (BASELINK_P (fn) && has_template_args)
      BASELINK_FUNCTIONS (fn)
        = build_nt (TEMPLATE_ID_EXPR,
  		  BASELINK_FUNCTIONS (fn),
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.873
diff -c -5 -p -r1.873 cp-tree.h
*** cp/cp-tree.h	11 Jul 2003 08:33:18 -0000	1.873
--- cp/cp-tree.h	14 Jul 2003 02:30:53 -0000
*************** struct tree_wrapper GTY(())
*** 348,357 ****
--- 348,371 ----
  {
    struct tree_common common;
    struct z_candidate *z_c;
  };
  
+ /* The different kinds of ids that we ecounter.  */
+ 
+ typedef enum cp_id_kind
+ {
+   /* Not an id at all.  */
+   CP_ID_KIND_NONE,
+   /* An unqualified-id that is not a template-id.  */
+   CP_ID_KIND_UNQUALIFIED,
+   /* An unqualified template-id.  */
+   CP_ID_KIND_TEMPLATE_ID,
+   /* A qualified-id.  */
+   CP_ID_KIND_QUALIFIED
+ } cp_id_kind;
+ 
  /* Macros for access to language-specific slots in an identifier.  */
  
  #define IDENTIFIER_NAMESPACE_BINDINGS(NODE)	\
    (LANG_IDENTIFIER_CAST (NODE)->namespace_bindings)
  #define IDENTIFIER_TEMPLATE(NODE)	\
*************** extern void yyungetc				(int, int);
*** 3881,3894 ****
  extern void snarf_method			(tree);
  
  extern void note_got_semicolon			(tree);
  extern void note_list_got_semicolon		(tree);
  extern void see_typename			(void);
! extern void unqualified_name_lookup_error       (tree);
! extern tree do_identifier			(tree, tree);
! extern tree do_scoped_id			(tree, tree);
! extern tree identifier_typedecl_value		(tree);
  extern tree build_lang_decl			(enum tree_code, tree, tree);
  extern void retrofit_lang_decl			(tree);
  extern tree copy_decl                           (tree);
  extern tree copy_type                           (tree);
  extern tree cxx_make_type			(enum tree_code);
--- 3895,3906 ----
  extern void snarf_method			(tree);
  
  extern void note_got_semicolon			(tree);
  extern void note_list_got_semicolon		(tree);
  extern void see_typename			(void);
! extern tree unqualified_name_lookup_error       (tree);
! extern tree unqualified_fn_lookup_error         (tree);
  extern tree build_lang_decl			(enum tree_code, tree, tree);
  extern void retrofit_lang_decl			(tree);
  extern tree copy_decl                           (tree);
  extern tree copy_type                           (tree);
  extern tree cxx_make_type			(enum tree_code);
*************** extern void maybe_process_partial_specia
*** 3961,3971 ****
  extern void maybe_check_template_type           (tree);
  extern tree most_specialized_instantiation      (tree);
  extern void print_candidates                    (tree);
  extern int instantiate_pending_templates        (void);
  extern tree tsubst_default_argument             (tree, tree, tree);
! extern tree tsubst_copy_and_build               (tree, tree, tsubst_flags_t, tree);
  extern tree most_general_template		(tree);
  extern tree get_mostly_instantiated_function_type (tree);
  extern int problematic_instantiation_changed    (void);
  extern void record_last_problematic_instantiation (void);
  extern tree current_instantiation               (void);
--- 3973,3983 ----
  extern void maybe_check_template_type           (tree);
  extern tree most_specialized_instantiation      (tree);
  extern void print_candidates                    (tree);
  extern int instantiate_pending_templates        (void);
  extern tree tsubst_default_argument             (tree, tree, tree);
! extern tree tsubst_copy_and_build               (tree, tree, tsubst_flags_t, tree, bool);
  extern tree most_general_template		(tree);
  extern tree get_mostly_instantiated_function_type (tree);
  extern int problematic_instantiation_changed    (void);
  extern void record_last_problematic_instantiation (void);
  extern tree current_instantiation               (void);
*************** extern bool any_type_dependent_arguments
*** 3980,3989 ****
--- 3992,4002 ----
  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);
+ extern bool reregister_specialization           (tree, tree, tree);
  
  /* in repo.c */
  extern void repo_template_used (tree);
  extern void repo_template_instantiated (tree, bool);
  extern void init_repo (const char *);
*************** extern void finish_label_decl           
*** 4109,4118 ****
--- 4122,4132 ----
  extern void finish_subobject                    (tree);
  extern tree finish_parenthesized_expr           (tree);
  extern tree finish_non_static_data_member       (tree, tree);
  extern tree begin_stmt_expr                     (void);
  extern tree finish_stmt_expr                    (tree);
+ extern tree perform_koenig_lookup               (tree, tree);
  extern tree finish_call_expr                    (tree, tree, bool);
  extern tree finish_increment_expr               (tree, enum tree_code);
  extern tree finish_this_expr                    (void);
  extern tree finish_object_call_expr             (tree, tree, tree);
  extern tree finish_pseudo_destructor_expr       (tree, tree, tree);
*************** extern tree finish_member_class_template
*** 4131,4140 ****
--- 4145,4158 ----
  extern void finish_template_decl                (tree);
  extern tree finish_template_type                (tree, tree, int);
  extern tree finish_base_specifier               (tree, tree, bool);
  extern void finish_member_declaration           (tree);
  extern void check_multiple_declarators          (void);
+ extern tree finish_id_expression                (tree, tree, tree,
+ 						 cp_id_kind *, tree *,
+ 						 bool, bool, bool *, 
+ 						 const char **);
  extern tree finish_typeof			(tree);
  extern tree finish_sizeof			(tree);
  extern tree finish_alignof			(tree);
  extern void finish_decl_cleanup                 (tree, tree);
  extern void finish_eh_cleanup                   (tree);
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1087
diff -c -5 -p -r1.1087 decl.c
*** cp/decl.c	11 Jul 2003 08:33:19 -0000	1.1087
--- cp/decl.c	14 Jul 2003 02:31:14 -0000
*************** duplicate_decls (tree newdecl, tree oldd
*** 3556,3595 ****
        memcpy ((char *) olddecl + sizeof (struct tree_common),
  	      (char *) newdecl + sizeof (struct tree_common),
  	      function_size - sizeof (struct tree_common));
  
        if (DECL_TEMPLATE_INSTANTIATION (newdecl))
! 	{
! 	  /* If newdecl is a template instantiation, it is possible that
! 	     the following sequence of events has occurred:
  
! 	     o A friend function was declared in a class template.  The
! 	     class template was instantiated.
  
! 	     o The instantiation of the friend declaration was
! 	     recorded on the instantiation list, and is newdecl.
  
! 	     o Later, however, instantiate_class_template called pushdecl
! 	     on the newdecl to perform name injection.  But, pushdecl in
! 	     turn called duplicate_decls when it discovered that another
! 	     declaration of a global function with the same name already
! 	     existed.
! 
! 	     o Here, in duplicate_decls, we decided to clobber newdecl.
! 
! 	     If we're going to do that, we'd better make sure that
! 	     olddecl, and not newdecl, is on the list of
! 	     instantiations so that if we try to do the instantiation
! 	     again we won't get the clobbered declaration.  */
! 
! 	  tree tmpl = DECL_TI_TEMPLATE (newdecl);
! 	  tree decls = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
! 
! 	  for (; decls; decls = TREE_CHAIN (decls))
! 	    if (TREE_VALUE (decls) == newdecl)
! 	      TREE_VALUE (decls) = olddecl;
! 	}
      }
    else
      {
        memcpy ((char *) olddecl + sizeof (struct tree_common),
  	      (char *) newdecl + sizeof (struct tree_common),
--- 3556,3589 ----
        memcpy ((char *) olddecl + sizeof (struct tree_common),
  	      (char *) newdecl + sizeof (struct tree_common),
  	      function_size - sizeof (struct tree_common));
  
        if (DECL_TEMPLATE_INSTANTIATION (newdecl))
! 	/* If newdecl is a template instantiation, it is possible that
! 	   the following sequence of events has occurred:
  
! 	   o A friend function was declared in a class template.  The
! 	   class template was instantiated.
  
! 	   o The instantiation of the friend declaration was
! 	   recorded on the instantiation list, and is newdecl.
  
! 	   o Later, however, instantiate_class_template called pushdecl
! 	   on the newdecl to perform name injection.  But, pushdecl in
! 	   turn called duplicate_decls when it discovered that another
! 	   declaration of a global function with the same name already
! 	   existed.
! 
! 	   o Here, in duplicate_decls, we decided to clobber newdecl.
! 
! 	   If we're going to do that, we'd better make sure that
! 	   olddecl, and not newdecl, is on the list of
! 	   instantiations so that if we try to do the instantiation
! 	   again we won't get the clobbered declaration.  */
! 	reregister_specialization (newdecl, 
! 				   DECL_TI_TEMPLATE (newdecl), 
! 				   olddecl);
      }
    else
      {
        memcpy ((char *) olddecl + sizeof (struct tree_common),
  	      (char *) newdecl + sizeof (struct tree_common),
Index: cp/lex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/lex.c,v
retrieving revision 1.309
diff -c -5 -p -r1.309 lex.c
*** cp/lex.c	7 Jul 2003 05:02:22 -0000	1.309
--- cp/lex.c	14 Jul 2003 02:31:15 -0000
*************** static void handle_pragma_vtable (cpp_re
*** 47,57 ****
  static void handle_pragma_unit (cpp_reader *);
  static void handle_pragma_interface (cpp_reader *);
  static void handle_pragma_implementation (cpp_reader *);
  static void handle_pragma_java_exceptions (cpp_reader *);
  
- static int is_global (tree);
  static void init_operators (void);
  static void copy_lang_type (tree);
  
  /* A constraint that can be tested at compile time.  */
  #define CONSTRAINT(name, expr) extern int constraint_##name [(expr) ? 1 : -1]
--- 47,56 ----
*************** handle_pragma_java_exceptions (cpp_reade
*** 660,693 ****
      warning ("junk at end of #pragma GCC java_exceptions");
  
    choose_personality_routine (lang_java);
  }
  
- /* Return true if d is in a global scope.  */
- 
- static int
- is_global (tree d)
- {
-   while (1)
-     switch (TREE_CODE (d))
-       {
-       case ERROR_MARK:
- 	return 1;
- 
-       case OVERLOAD: d = OVL_FUNCTION (d); continue;
-       case TREE_LIST: d = TREE_VALUE (d); continue;
-       default:
-         my_friendly_assert (DECL_P (d), 980629);
- 
- 	return DECL_NAMESPACE_SCOPE_P (d);
-       }
- }
- 
  /* Issue an error message indicating that the lookup of NAME (an
!    IDENTIFIER_NODE) failed.  */
  
! void
  unqualified_name_lookup_error (tree name)
  {
    if (IDENTIFIER_OPNAME_P (name))
      {
        if (name != ansi_opname (ERROR_MARK))
--- 659,672 ----
      warning ("junk at end of #pragma GCC java_exceptions");
  
    choose_personality_routine (lang_java);
  }
  
  /* Issue an error message indicating that the lookup of NAME (an
!    IDENTIFIER_NODE) failed.  Returns the ERROR_MARK_NODE.  */
  
! tree
  unqualified_name_lookup_error (tree name)
  {
    if (IDENTIFIER_OPNAME_P (name))
      {
        if (name != ansi_opname (ERROR_MARK))
*************** unqualified_name_lookup_error (tree name
*** 712,879 ****
  	}
        /* Prevent repeated error messages.  */
        SET_IDENTIFIER_NAMESPACE_VALUE (name, error_mark_node);
        SET_IDENTIFIER_ERROR_LOCUS (name, current_function_decl);
      }
- }
- 
- tree
- do_identifier (register tree token, tree args)
- {
-   register tree id;
- 
-   timevar_push (TV_NAME_LOOKUP);
-   id = lookup_name (token, 0);
- 
-   /* Do Koenig lookup if appropriate (inside templates we build lookup
-      expressions instead).
  
!      [basic.lookup.koenig]: If the ordinary unqualified lookup of the name
!      finds the declaration of a class member function, the associated
!      namespaces and classes are not considered.  */
! 
!   if (args && !current_template_parms && (!id || is_global (id)))
!     id = lookup_arg_dependent (token, id, args);
! 
!   if (id == error_mark_node)
!     {
!       /* lookup_name quietly returns error_mark_node if we're parsing,
! 	 as we don't want to complain about an identifier that ends up
! 	 being used as a declarator.  So we call it again to get the error
! 	 message.  */
!       id = lookup_name (token, 0);
!       POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
!     }
! 
!   if (!id || (TREE_CODE (id) == FUNCTION_DECL
! 	      && DECL_ANTICIPATED (id)))
!     {
!       if (current_template_parms)
!         POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP,
!                                 build_min_nt (LOOKUP_EXPR, token));
!       else if (IDENTIFIER_TYPENAME_P (token))
! 	/* A templated conversion operator might exist.  */
! 	POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, token);
!       else
! 	{
! 	  unqualified_name_lookup_error (token);
! 	  POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
! 	}
!     }
! 
!   id = check_for_out_of_scope_variable (id);
! 
!   /* TREE_USED is set in `hack_identifier'.  */
!   if (TREE_CODE (id) == CONST_DECL)
!     {
!       /* Check access.  */
!       if (IDENTIFIER_CLASS_VALUE (token) == id)
! 	perform_or_defer_access_check (TYPE_BINFO (DECL_CONTEXT (id)), id);
!       if (!processing_template_decl || DECL_TEMPLATE_PARM_P (id))
! 	id = DECL_INITIAL (id);
!     }
!   else
!     id = hack_identifier (id, token);
! 
!   /* We must look up dependent names when the template is
!      instantiated, not while parsing it.  For now, we don't
!      distinguish between dependent and independent names.  So, for
!      example, we look up all overloaded functions at
!      instantiation-time, even though in some cases we should just use
!      the DECL we have here.  We also use LOOKUP_EXPRs to find things
!      like local variables, rather than creating TEMPLATE_DECLs for the
!      local variables and then finding matching instantiations.  */
!   if (current_template_parms
!       && (is_overloaded_fn (id)
! 	  || (TREE_CODE (id) == VAR_DECL
! 	      && CP_DECL_CONTEXT (id)
! 	      && TREE_CODE (CP_DECL_CONTEXT (id)) == FUNCTION_DECL)
! 	  || TREE_CODE (id) == PARM_DECL
! 	  || TREE_CODE (id) == RESULT_DECL
! 	  || TREE_CODE (id) == USING_DECL))
!     id = build_min_nt (LOOKUP_EXPR, token);
! 
!   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, id);
  }
  
  tree
! do_scoped_id (tree token, tree id)
  {
-   timevar_push (TV_NAME_LOOKUP);
-   if (!id || (TREE_CODE (id) == FUNCTION_DECL
- 	      && DECL_ANTICIPATED (id)))
-     {
-       if (processing_template_decl)
- 	{
- 	  id = build_min_nt (LOOKUP_EXPR, token);
- 	  LOOKUP_EXPR_GLOBAL (id) = 1;
- 	  POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, id);
- 	}
-       if (IDENTIFIER_NAMESPACE_VALUE (token) != error_mark_node)
-         error ("`::%D' undeclared (first use here)", token);
-       id = error_mark_node;
-       /* Prevent repeated error messages.  */
-       SET_IDENTIFIER_NAMESPACE_VALUE (token, error_mark_node);
-     }
-   else
-     {
-       if (TREE_CODE (id) == ADDR_EXPR)
- 	mark_used (TREE_OPERAND (id, 0));
-       else if (TREE_CODE (id) != OVERLOAD)
- 	mark_used (id);
-     }
-   if (TREE_CODE (id) == CONST_DECL && ! processing_template_decl)
-     {
-       /* XXX CHS - should we set TREE_USED of the constant? */
-       id = DECL_INITIAL (id);
-       /* This is to prevent an enum whose value is 0
- 	 from being considered a null pointer constant.  */
-       id = build1 (NOP_EXPR, TREE_TYPE (id), id);
-       TREE_CONSTANT (id) = 1;
-     }
- 
    if (processing_template_decl)
      {
!       if (is_overloaded_fn (id))
  	{
! 	  id = build_min_nt (LOOKUP_EXPR, token);
! 	  LOOKUP_EXPR_GLOBAL (id) = 1;
! 	  POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, id);
  	}
!       /* else just use the decl */
      }
-   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, convert_from_reference (id));
- }
- 
- tree
- identifier_typedecl_value (tree node)
- {
-   tree t, type;
-   type = IDENTIFIER_TYPE_VALUE (node);
-   if (type == NULL_TREE)
-     return NULL_TREE;
- 
-   if (IDENTIFIER_BINDING (node))
-     {
-       t = IDENTIFIER_VALUE (node);
-       if (t && TREE_CODE (t) == TYPE_DECL && TREE_TYPE (t) == type)
- 	return t;
-     }
-   if (IDENTIFIER_NAMESPACE_VALUE (node))
-     {
-       t = IDENTIFIER_NAMESPACE_VALUE (node);
-       if (t && TREE_CODE (t) == TYPE_DECL && TREE_TYPE (t) == type)
- 	return t;
-     }
- 
-   /* Will this one ever happen?  */
-   if (TYPE_MAIN_DECL (type))
-     return TYPE_MAIN_DECL (type);
  
!   /* We used to do an internal error of 62 here, but instead we will
!      handle the return of a null appropriately in the callers.  */
!   return NULL_TREE;
  }
  
  #ifdef GATHER_STATISTICS
  /* The original for tree_node_kind is in the toplevel tree.c; changes there
     need to be brought into here, unless this were actually put into a header
--- 691,737 ----
  	}
        /* Prevent repeated error messages.  */
        SET_IDENTIFIER_NAMESPACE_VALUE (name, error_mark_node);
        SET_IDENTIFIER_ERROR_LOCUS (name, current_function_decl);
      }
  
!   return error_mark_node;
  }
  
+ /* Like unqualified_name_lookup_error, but NAME is an unqualified-id
+    used as a function.  Returns an appropriate expression for
+    NAME.  */
+ 
  tree
! unqualified_fn_lookup_error (tree name)
  {
    if (processing_template_decl)
      {
!       /* In a template, it is invalid to write "f()" or "f(3)" if no
! 	 declaration of "f" is available.  Historically, G++ and most
! 	 other compilers accepted that usage; explain to the user what
! 	 is going wrong.  */
!       (flag_permissive ? warning : error)
! 	("there are no arguments to `%D' that depend on a template "
! 	 "parameter, so a declaration of `%D' must be available", name,
! 	 name);
!       
!       if (!flag_permissive)
  	{
! 	  static bool hint;
! 	  if (!hint)
! 	    {
! 	      error ("(if you use `-fpermissive', G++ will accept your code, "
! 		     "but allowing the use of an undeclared name is "
! 		     "deprecated)");
! 	      hint = true;
! 	    }
  	}
!       return build_min_nt (LOOKUP_EXPR, name);
      }
  
!   return unqualified_name_lookup_error (name);
  }
  
  #ifdef GATHER_STATISTICS
  /* The original for tree_node_kind is in the toplevel tree.c; changes there
     need to be brought into here, unless this were actually put into a header
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.81
diff -c -5 -p -r1.81 parser.c
*** cp/parser.c	11 Jul 2003 09:17:58 -0000	1.81
--- cp/parser.c	14 Jul 2003 02:31:37 -0000
*************** typedef enum cp_parser_flags
*** 1045,1068 ****
    CP_PARSER_FLAGS_OPTIONAL = 0x1,
    /* When parsing a type-specifier, do not allow user-defined types.  */
    CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2
  } cp_parser_flags;
  
- /* The different kinds of ids that we ecounter.  */
- 
- typedef enum cp_parser_id_kind
- {
-   /* Not an id at all.  */
-   CP_PARSER_ID_KIND_NONE,
-   /* An unqualified-id that is not a template-id.  */
-   CP_PARSER_ID_KIND_UNQUALIFIED,
-   /* An unqualified template-id.  */
-   CP_PARSER_ID_KIND_TEMPLATE_ID,
-   /* A qualified-id.  */
-   CP_PARSER_ID_KIND_QUALIFIED
- } cp_parser_id_kind;
- 
  /* The different kinds of declarators we want to parse.  */
  
  typedef enum cp_parser_declarator_kind
  {
    /* We want an abstract declartor.  */
--- 1045,1054 ----
*************** static bool cp_parser_translation_unit
*** 1309,1319 ****
    (cp_parser *);
  
  /* Expressions [gram.expr]  */
  
  static tree cp_parser_primary_expression
!   (cp_parser *, cp_parser_id_kind *, tree *);
  static tree cp_parser_id_expression
    (cp_parser *, bool, bool, bool *);
  static tree cp_parser_unqualified_id
    (cp_parser *, bool, bool);
  static tree cp_parser_nested_name_specifier_opt
--- 1295,1305 ----
    (cp_parser *);
  
  /* Expressions [gram.expr]  */
  
  static tree cp_parser_primary_expression
!   (cp_parser *, cp_id_kind *, tree *);
  static tree cp_parser_id_expression
    (cp_parser *, bool, bool, bool *);
  static tree cp_parser_unqualified_id
    (cp_parser *, bool, bool);
  static tree cp_parser_nested_name_specifier_opt
*************** static bool cp_parser_simulate_error
*** 1693,1704 ****
    (cp_parser *);
  static void cp_parser_check_type_definition
    (cp_parser *);
  static tree cp_parser_non_constant_expression
    (const char *);
- static tree cp_parser_non_constant_id_expression
-   (tree);
  static bool cp_parser_diagnose_invalid_type_name
    (cp_parser *);
  static int cp_parser_skip_to_closing_parenthesis
    (cp_parser *, bool, bool);
  static void cp_parser_skip_to_end_of_statement
--- 1679,1688 ----
*************** cp_parser_non_constant_expression (const
*** 1792,1811 ****
  {
    error ("%s cannot appear in a constant-expression", thing);
    return error_mark_node;
  }
  
- /* Issue an eror message about the fact that DECL appeared in a
-    constant-expression.  Returns ERROR_MARK_NODE.  */
- 
- static tree
- cp_parser_non_constant_id_expression (tree decl)
- {
-   error ("`%D' cannot appear in a constant-expression", decl);
-   return error_mark_node;
- }
- 
  /* Check for a common situation where a type-name should be present,
     but is not, and issue a sensible error message.  Returns true if an
     invalid type-name was detected.  */
  
  static bool
--- 1776,1785 ----
*************** cp_parser_translation_unit (cp_parser* p
*** 2213,2229 ****
     *QUALIFYING_CLASS gives the class that is used as the qualifying
     class in the pointer-to-member.  */
  
  static tree
  cp_parser_primary_expression (cp_parser *parser, 
! 			      cp_parser_id_kind *idk,
  			      tree *qualifying_class)
  {
    cp_token *token;
  
    /* Assume the primary expression is not an id-expression.  */
!   *idk = CP_PARSER_ID_KIND_NONE;
    /* And that it cannot be used as pointer-to-member.  */
    *qualifying_class = NULL_TREE;
  
    /* Peek at the next token.  */
    token = cp_lexer_peek_token (parser->lexer);
--- 2187,2203 ----
     *QUALIFYING_CLASS gives the class that is used as the qualifying
     class in the pointer-to-member.  */
  
  static tree
  cp_parser_primary_expression (cp_parser *parser, 
! 			      cp_id_kind *idk,
  			      tree *qualifying_class)
  {
    cp_token *token;
  
    /* Assume the primary expression is not an id-expression.  */
!   *idk = CP_ID_KIND_NONE;
    /* And that it cannot be used as pointer-to-member.  */
    *qualifying_class = NULL_TREE;
  
    /* Peek at the next token.  */
    token = cp_lexer_peek_token (parser->lexer);
*************** cp_parser_primary_expression (cp_parser 
*** 2395,2404 ****
--- 2369,2379 ----
      case CPP_TEMPLATE_ID:
      case CPP_NESTED_NAME_SPECIFIER:
        {
  	tree id_expression;
  	tree decl;
+ 	const char *error_msg;
  
        id_expression:
  	/* Parse the id-expression.  */
  	id_expression 
  	  = cp_parser_id_expression (parser, 
*************** cp_parser_primary_expression (cp_parser 
*** 2455,2739 ****
  		    error ("local variable `%D' may not appear in this context",
  			   decl);
  		    return error_mark_node;
  		  }
  	      }
- 
- 	    if (decl == error_mark_node)
- 	      {
- 		/* Name lookup failed.  */
- 		if (!parser->scope 
- 		    && processing_template_decl)
- 		  {
- 		    /* Unqualified name lookup failed while processing a
- 		       template.  */
- 		    *idk = CP_PARSER_ID_KIND_UNQUALIFIED;
- 		    /* If the next token is a parenthesis, assume that
- 		       Koenig lookup will succeed when instantiating the
- 		       template.  */
- 		    if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
- 		      return build_min_nt (LOOKUP_EXPR, id_expression);
- 		    /* If we're not doing Koenig lookup, issue an error.  */
- 		    error ("`%D' has not been declared", id_expression);
- 		    return error_mark_node;
- 		  }
- 		else if (parser->scope
- 			 && (!TYPE_P (parser->scope)
- 			     || !dependent_type_p (parser->scope)))
- 		  {
- 		    /* Qualified name lookup failed, and the
- 		       qualifying name was not a dependent type.  That
- 		       is always an error.  */
- 		    if (TYPE_P (parser->scope)
- 			&& !COMPLETE_TYPE_P (parser->scope))
- 		      error ("incomplete type `%T' used in nested name "
- 			     "specifier",
- 			     parser->scope);
- 		    else if (parser->scope != global_namespace)
- 		      error ("`%D' is not a member of `%D'",
- 			     id_expression, parser->scope);
- 		    else
- 		      error ("`::%D' has not been declared", id_expression);
- 		    return error_mark_node;
- 		  }
- 		else if (!parser->scope && !processing_template_decl)
- 		  {
- 		    /* It may be resolvable as a koenig lookup function
- 		       call.  */
- 		    *idk = CP_PARSER_ID_KIND_UNQUALIFIED;
- 		    return id_expression;
- 		  }
- 	      }
- 	    /* If DECL is a variable that would be out of scope under
- 	       ANSI/ISO rules, but in scope in the ARM, name lookup
- 	       will succeed.  Issue a diagnostic here.  */
- 	    else
- 	      decl = check_for_out_of_scope_variable (decl);
- 
- 	    /* Remember that the name was used in the definition of
- 	       the current class so that we can check later to see if
- 	       the meaning would have been different after the class
- 	       was entirely defined.  */
- 	    if (!parser->scope && decl != error_mark_node)
- 	      maybe_note_name_used_in_class (id_expression, decl);
- 	  }
- 
- 	/* If we didn't find anything, or what we found was a type,
- 	   then this wasn't really an id-expression.  */
- 	if (TREE_CODE (decl) == TEMPLATE_DECL
- 	    && !DECL_FUNCTION_TEMPLATE_P (decl))
- 	  {
- 	    cp_parser_error (parser, "missing template arguments");
- 	    return error_mark_node;
- 	  }
- 	else if (TREE_CODE (decl) == TYPE_DECL
- 		 || TREE_CODE (decl) == NAMESPACE_DECL)
- 	  {
- 	    cp_parser_error (parser, 
- 			     "expected primary-expression");
- 	    return error_mark_node;
- 	  }
- 
- 	/* If the name resolved to a template parameter, there is no
- 	   need to look it up again later.  Similarly, we resolve
- 	   enumeration constants to their underlying values.  */
- 	if (TREE_CODE (decl) == CONST_DECL)
- 	  {
- 	    *idk = CP_PARSER_ID_KIND_NONE;
- 	    if (DECL_TEMPLATE_PARM_P (decl) || !processing_template_decl)
- 	      return DECL_INITIAL (decl);
- 	    return decl;
- 	  }
- 	else
- 	  {
- 	    bool dependent_p;
- 
- 	    /* If the declaration was explicitly qualified indicate
- 	       that.  The semantics of `A::f(3)' are different than
- 	       `f(3)' if `f' is virtual.  */
- 	    *idk = (parser->scope 
- 		    ? CP_PARSER_ID_KIND_QUALIFIED
- 		    : (TREE_CODE (decl) == TEMPLATE_ID_EXPR
- 		       ? CP_PARSER_ID_KIND_TEMPLATE_ID
- 		       : CP_PARSER_ID_KIND_UNQUALIFIED));
- 
- 
- 	    /* [temp.dep.expr]
- 	       
- 	       An id-expression is type-dependent if it contains an
- 	       identifier that was declared with a dependent type.
- 	       
- 	       As an optimization, we could choose not to create a
- 	       LOOKUP_EXPR for a name that resolved to a local
- 	       variable in the template function that we are currently
- 	       declaring; such a name cannot ever resolve to anything
- 	       else.  If we did that we would not have to look up
- 	       these names at instantiation time.
- 	       
- 	       The standard is not very specific about an
- 	       id-expression that names a set of overloaded functions.
- 	       What if some of them have dependent types and some of
- 	       them do not?  Presumably, such a name should be treated
- 	       as a dependent name.  */
- 	    /* Assume the name is not dependent.  */
- 	    dependent_p = false;
- 	    if (!processing_template_decl)
- 	      /* No names are dependent outside a template.  */
- 	      ;
- 	    /* A template-id where the name of the template was not
- 	       resolved is definitely dependent.  */
- 	    else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
- 		     && (TREE_CODE (TREE_OPERAND (decl, 0)) 
- 			 == IDENTIFIER_NODE))
- 	      dependent_p = true;
- 	    /* For anything except an overloaded function, just check
- 	       its type.  */
- 	    else if (!is_overloaded_fn (decl))
- 	      dependent_p 
- 		= dependent_type_p (TREE_TYPE (decl));
- 	    /* For a set of overloaded functions, check each of the
- 	       functions.  */
- 	    else
- 	      {
- 		tree fns = decl;
- 
- 		if (BASELINK_P (fns))
- 		  fns = BASELINK_FUNCTIONS (fns);
- 		  
- 		/* 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);
- 		  }
- 
- 		/* If there are no dependent template arguments, go
- 		   through the overlaoded functions.  */
- 		while (fns && !dependent_p)
- 		  {
- 		    tree fn = OVL_CURRENT (fns);
- 		    
- 		    /* Member functions of dependent classes are
- 		       dependent.  */
- 		    if (TREE_CODE (fn) == FUNCTION_DECL
- 			&& type_dependent_expression_p (fn))
- 		      dependent_p = true;
- 		    else if (TREE_CODE (fn) == TEMPLATE_DECL
- 			     && dependent_template_p (fn))
- 		      dependent_p = true;
- 		    
- 		    fns = OVL_NEXT (fns);
- 		  }
- 	      }
- 
- 	    /* If the name was dependent on a template parameter,
- 	       we will resolve the name at instantiation time.  */
- 	    if (dependent_p)
- 	      {
- 		/* Create a SCOPE_REF for qualified names, if the
- 		   scope is dependent.  */
- 		if (parser->scope)
- 		  {
- 		    if (TYPE_P (parser->scope))
- 		      *qualifying_class = parser->scope;
- 		    /* Since this name was dependent, the expression isn't
- 		       constant -- yet.  No error is issued because it
- 		       might be constant when things are instantiated.  */
- 		    if (parser->constant_expression_p)
- 		      parser->non_constant_expression_p = true;
- 		    if (TYPE_P (parser->scope)
- 			&& dependent_type_p (parser->scope))
- 		      return build_nt (SCOPE_REF, 
- 				       parser->scope, 
- 				       id_expression);
- 		    else if (TYPE_P (parser->scope)
- 			     && DECL_P (decl))
- 		      return build (SCOPE_REF,
- 				    TREE_TYPE (decl),
- 				    parser->scope,
- 				    id_expression);
- 		    else
- 		      return decl;
- 		  }
- 		/* A TEMPLATE_ID already contains all the information
- 		   we need.  */
- 		if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR)
- 		  return id_expression;
- 		/* Since this name was dependent, the expression isn't
- 		   constant -- yet.  No error is issued because it
- 		   might be constant when things are instantiated.  */
- 		if (parser->constant_expression_p)
- 		  parser->non_constant_expression_p = true;
- 		/* Create a LOOKUP_EXPR for other unqualified names.  */
- 		return build_min_nt (LOOKUP_EXPR, id_expression);
- 	      }
- 
- 	    /* 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 
- 			(decl, parser->scope, current_class_type));
- 		if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (decl))
- 		  *qualifying_class = parser->scope;
- 		else if (!processing_template_decl)
- 		  decl = convert_from_reference (decl);
- 		else if (TYPE_P (parser->scope))
- 		  decl = build (SCOPE_REF,
- 				TREE_TYPE (decl),
- 				parser->scope,
- 				decl);
- 	      }
- 	    else
- 	      /* Transform references to non-static data members into
- 		 COMPONENT_REFs.  */
- 	      decl = hack_identifier (decl, id_expression);
- 
- 	    /* Resolve references to variables of anonymous unions
- 	       into COMPONENT_REFs.  */
- 	    if (TREE_CODE (decl) == ALIAS_DECL)
- 	      decl = DECL_INITIAL (decl);
  	  }
! 
! 	if (TREE_DEPRECATED (decl))
! 	  warn_deprecated_use (decl);
! 
  	return decl;
        }
  
        /* Anything else is an error.  */
      default:
--- 2430,2449 ----
  		    error ("local variable `%D' may not appear in this context",
  			   decl);
  		    return error_mark_node;
  		  }
  	      }
  	  }
! 	
! 	decl = finish_id_expression (id_expression, decl, parser->scope, 
! 				     idk, qualifying_class,
! 				     parser->constant_expression_p,
! 				     parser->allow_non_constant_expression_p,
! 				     &parser->non_constant_expression_p,
! 				     &error_msg);
! 	if (error_msg)
! 	  cp_parser_error (parser, error_msg);
  	return decl;
        }
  
        /* Anything else is an error.  */
      default:
*************** cp_parser_class_or_namespace_name (cp_pa
*** 3461,3471 ****
  static tree
  cp_parser_postfix_expression (cp_parser *parser, bool address_p)
  {
    cp_token *token;
    enum rid keyword;
!   cp_parser_id_kind idk = CP_PARSER_ID_KIND_NONE;
    tree postfix_expression = NULL_TREE;
    /* Non-NULL only if the current postfix-expression can be used to
       form a pointer-to-member.  In that case, QUALIFYING_CLASS is the
       class used to qualify the member.  */
    tree qualifying_class = NULL_TREE;
--- 3171,3181 ----
  static tree
  cp_parser_postfix_expression (cp_parser *parser, bool address_p)
  {
    cp_token *token;
    enum rid keyword;
!   cp_id_kind idk = CP_ID_KIND_NONE;
    tree postfix_expression = NULL_TREE;
    /* Non-NULL only if the current postfix-expression can be used to
       form a pointer-to-member.  In that case, QUALIFYING_CLASS is the
       class used to qualify the member.  */
    tree qualifying_class = NULL_TREE;
*************** cp_parser_postfix_expression (cp_parser 
*** 3728,3742 ****
    /* Keep looping until the postfix-expression is complete.  */
    while (true)
      {
        if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE
  	  && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
! 	{
! 	  /* It is not a Koenig lookup function call.  */
! 	  unqualified_name_lookup_error (postfix_expression);
! 	  postfix_expression = error_mark_node;
! 	}
        
        /* Peek at the next token.  */
        token = cp_lexer_peek_token (parser->lexer);
  
        switch (token->type)
--- 3438,3450 ----
    /* Keep looping until the postfix-expression is complete.  */
    while (true)
      {
        if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE
  	  && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
! 	/* It is not a Koenig lookup function call.  */
! 	postfix_expression 
! 	  = unqualified_name_lookup_error (postfix_expression);
        
        /* Peek at the next token.  */
        token = cp_lexer_peek_token (parser->lexer);
  
        switch (token->type)
*************** cp_parser_postfix_expression (cp_parser 
*** 3754,3764 ****
  	    cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
  
  	    /* Build the ARRAY_REF.  */
  	    postfix_expression 
  	      = grok_array_decl (postfix_expression, index);
! 	    idk = CP_PARSER_ID_KIND_NONE;
  	  }
  	  break;
  
  	case CPP_OPEN_PAREN:
  	  /* postfix-expression ( expression-list [opt] ) */
--- 3462,3472 ----
  	    cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
  
  	    /* Build the ARRAY_REF.  */
  	    postfix_expression 
  	      = grok_array_decl (postfix_expression, index);
! 	    idk = CP_ID_KIND_NONE;
  	  }
  	  break;
  
  	case CPP_OPEN_PAREN:
  	  /* postfix-expression ( expression-list [opt] ) */
*************** cp_parser_postfix_expression (cp_parser 
*** 3778,3839 ****
  		if (!parser->allow_non_constant_expression_p)
  		  return cp_parser_non_constant_expression ("a function call");
  		parser->non_constant_expression_p = true;
  	      }
  
! 	    if (idk == CP_PARSER_ID_KIND_UNQUALIFIED
  		&& (is_overloaded_fn (postfix_expression)
  		    || DECL_P (postfix_expression)
  		    || TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
  		&& args)
! 	      {
! 		tree identifier = NULL_TREE;
! 		tree functions = NULL_TREE;
! 
! 		/* Find the name of the overloaded function.  */
! 		if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
! 		  identifier = postfix_expression;
! 		else if (is_overloaded_fn (postfix_expression))
! 		  {
! 		    functions = postfix_expression;
! 		    identifier = DECL_NAME (get_first_fn (functions));
! 		  }
! 		else if (DECL_P (postfix_expression))
! 		  {
! 		    functions = postfix_expression;
! 		    identifier = DECL_NAME (postfix_expression);
! 		  }
! 
! 		/* 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);
--- 3486,3506 ----
  		if (!parser->allow_non_constant_expression_p)
  		  return cp_parser_non_constant_expression ("a function call");
  		parser->non_constant_expression_p = true;
  	      }
  
! 	    if (idk == CP_ID_KIND_UNQUALIFIED
  		&& (is_overloaded_fn (postfix_expression)
  		    || DECL_P (postfix_expression)
  		    || TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
  		&& args)
! 	      postfix_expression 
! 		= perform_koenig_lookup (postfix_expression, args);
! 	    else if (idk == CP_ID_KIND_UNQUALIFIED 
  		     && TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
! 	      postfix_expression
! 		= unqualified_fn_lookup_error (postfix_expression);
  
  	    if (TREE_CODE (postfix_expression) == COMPONENT_REF)
  	      {
  		tree instance = TREE_OPERAND (postfix_expression, 0);
  		tree fn = TREE_OPERAND (postfix_expression, 1);
*************** cp_parser_postfix_expression (cp_parser 
*** 3851,3869 ****
  		  }
  		  
  		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.  */
  	      postfix_expression
  		= finish_call_expr (postfix_expression, args,
  				    /*disallow_virtual=*/true);
--- 3518,3536 ----
  		  }
  		  
  		postfix_expression
  		  = (build_new_method_call 
  		     (instance, fn, args, NULL_TREE, 
! 		      (idk == CP_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_ID_KIND_QUALIFIED)
  	      /* A call to a static class member, or a namespace-scope
  		 function.  */
  	      postfix_expression
  		= finish_call_expr (postfix_expression, args,
  				    /*disallow_virtual=*/true);
*************** cp_parser_postfix_expression (cp_parser 
*** 3872,3882 ****
  	      postfix_expression 
  		= finish_call_expr (postfix_expression, args, 
  				    /*disallow_virtual=*/false);
  
  	    /* The POSTFIX_EXPRESSION is certainly no longer an id.  */
! 	    idk = CP_PARSER_ID_KIND_NONE;
  	  }
  	  break;
  	  
  	case CPP_DOT:
  	case CPP_DEREF:
--- 3539,3549 ----
  	      postfix_expression 
  		= finish_call_expr (postfix_expression, args, 
  				    /*disallow_virtual=*/false);
  
  	    /* The POSTFIX_EXPRESSION is certainly no longer an id.  */
! 	    idk = CP_ID_KIND_NONE;
  	  }
  	  break;
  	  
  	case CPP_DOT:
  	case CPP_DEREF:
*************** cp_parser_postfix_expression (cp_parser 
*** 3899,3909 ****
  	    /* The identifier following the `->' or `.' is not
  	       qualified.  */
  	    parser->scope = NULL_TREE;
  	    parser->qualifying_scope = NULL_TREE;
  	    parser->object_scope = NULL_TREE;
! 	    idk = CP_PARSER_ID_KIND_NONE;
  	    /* Enter the scope corresponding to the type of the object
  	       given by the POSTFIX_EXPRESSION.  */
  	    if (!dependent_p 
  		&& TREE_TYPE (postfix_expression) != NULL_TREE)
  	      {
--- 3566,3576 ----
  	    /* The identifier following the `->' or `.' is not
  	       qualified.  */
  	    parser->scope = NULL_TREE;
  	    parser->qualifying_scope = NULL_TREE;
  	    parser->object_scope = NULL_TREE;
! 	    idk = CP_ID_KIND_NONE;
  	    /* Enter the scope corresponding to the type of the object
  	       given by the POSTFIX_EXPRESSION.  */
  	    if (!dependent_p 
  		&& TREE_TYPE (postfix_expression) != NULL_TREE)
  	      {
*************** cp_parser_postfix_expression (cp_parser 
*** 3967,3977 ****
  		   include scope information.  */
  
  		/* But we do need to remember that there was an explicit
  		   scope for virtual function calls.  */
  		if (parser->scope)
! 		  idk = CP_PARSER_ID_KIND_QUALIFIED;
  
  		if (name != error_mark_node 
  		    && !BASELINK_P (name)
  		    && parser->scope)
  		  {
--- 3634,3644 ----
  		   include scope information.  */
  
  		/* But we do need to remember that there was an explicit
  		   scope for virtual function calls.  */
  		if (parser->scope)
! 		  idk = CP_ID_KIND_QUALIFIED;
  
  		if (name != error_mark_node 
  		    && !BASELINK_P (name)
  		    && parser->scope)
  		  {
*************** cp_parser_postfix_expression (cp_parser 
*** 4017,4027 ****
  	    }
  	  /* Generate a representation for the complete expression.  */
  	  postfix_expression 
  	    = finish_increment_expr (postfix_expression, 
  				     POSTINCREMENT_EXPR);
! 	  idk = CP_PARSER_ID_KIND_NONE;
  	  break;
  
  	case CPP_MINUS_MINUS:
  	  /* postfix-expression -- */
  	  /* Consume the `--' token.  */
--- 3684,3694 ----
  	    }
  	  /* Generate a representation for the complete expression.  */
  	  postfix_expression 
  	    = finish_increment_expr (postfix_expression, 
  				     POSTINCREMENT_EXPR);
! 	  idk = CP_ID_KIND_NONE;
  	  break;
  
  	case CPP_MINUS_MINUS:
  	  /* postfix-expression -- */
  	  /* Consume the `--' token.  */
*************** cp_parser_postfix_expression (cp_parser 
*** 4035,4045 ****
  	    }
  	  /* Generate a representation for the complete expression.  */
  	  postfix_expression 
  	    = finish_increment_expr (postfix_expression, 
  				     POSTDECREMENT_EXPR);
! 	  idk = CP_PARSER_ID_KIND_NONE;
  	  break;
  
  	default:
  	  return postfix_expression;
  	}
--- 3702,3712 ----
  	    }
  	  /* Generate a representation for the complete expression.  */
  	  postfix_expression 
  	    = finish_increment_expr (postfix_expression, 
  				     POSTDECREMENT_EXPR);
! 	  idk = CP_ID_KIND_NONE;
  	  break;
  
  	default:
  	  return postfix_expression;
  	}
*************** cp_parser_template_argument (cp_parser* 
*** 8063,8073 ****
  {
    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.  
  
--- 7730,7740 ----
  {
    tree argument;
    bool template_p;
    bool address_p;
    cp_token *token;
!   cp_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.  
  
*************** cp_parser_fold_non_dependent_expr (tree 
*** 14182,14192 ****
        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;
  }
  
--- 13849,13860 ----
        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,
! 				    /*function_p=*/false);
        processing_template_decl = saved_processing_template_decl;
      }
    return expr;
  }
  
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.721
diff -c -5 -p -r1.721 pt.c
*** cp/pt.c	13 Jul 2003 15:20:58 -0000	1.721
--- cp/pt.c	14 Jul 2003 02:31:56 -0000
*************** static int inline_needs_template_parms (
*** 123,133 ****
  static void push_inline_template_parms_recursive (tree, int);
  static tree retrieve_specialization (tree, tree);
  static tree retrieve_local_specialization (tree);
  static tree register_specialization (tree, tree, tree);
  static void register_local_specialization (tree, tree);
- static int unregister_specialization (tree, tree);
  static tree reduce_template_parm_level (tree, tree, int);
  static tree build_template_decl (tree, tree);
  static int mark_template_parm (tree, void *);
  static int template_parm_this_level_p (tree, void *);
  static tree tsubst_friend_function (tree, tree);
--- 123,132 ----
*************** register_specialization (tree spec, tree
*** 985,1008 ****
  
    return spec;
  }
  
  /* Unregister the specialization SPEC as a specialization of TMPL.
!    Returns nonzero if the SPEC was listed as a specialization of
!    TMPL.  */
  
! static int
! unregister_specialization (tree spec, tree tmpl)
  {
    tree* s;
  
    for (s = &DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
         *s != NULL_TREE;
         s = &TREE_CHAIN (*s))
      if (TREE_VALUE (*s) == spec)
        {
! 	*s = TREE_CHAIN (*s);
  	return 1;
        }
  
    return 0;
  }
--- 984,1010 ----
  
    return spec;
  }
  
  /* Unregister the specialization SPEC as a specialization of TMPL.
!    Replace it with NEW_SPEC, if NEW_SPEC is non-NULL.  Returns true
!    if the SPEC was listed as a specialization of TMPL.  */
  
! bool
! reregister_specialization (tree spec, tree tmpl, tree new_spec)
  {
    tree* s;
  
    for (s = &DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
         *s != NULL_TREE;
         s = &TREE_CHAIN (*s))
      if (TREE_VALUE (*s) == spec)
        {
! 	if (!new_spec)
! 	  *s = TREE_CHAIN (*s);
! 	else
! 	  TREE_VALUE (*s) == new_spec;
  	return 1;
        }
  
    return 0;
  }
*************** tsubst_friend_function (tree decl, tree 
*** 4908,4919 ****
  		 any, with the new template information pertaining to
  		 the declaration.  */
  	      DECL_TEMPLATE_INFO (old_decl) = new_friend_template_info;
  
  	      if (TREE_CODE (old_decl) != TEMPLATE_DECL)
! 		/* duplicate_decls will take care of this case.  */
! 		;
  	      else 
  		{
  		  tree t;
  		  tree new_friend_args;
  
--- 4910,4930 ----
  		 any, with the new template information pertaining to
  		 the declaration.  */
  	      DECL_TEMPLATE_INFO (old_decl) = new_friend_template_info;
  
  	      if (TREE_CODE (old_decl) != TEMPLATE_DECL)
! 		{
! 		  tree t;
! 		  tree spec;
! 
! 		  t = most_general_template (old_decl);
! 		  for (spec = DECL_TEMPLATE_SPECIALIZATIONS (t);
! 		       spec;
! 		       spec = TREE_CHAIN (spec))
! 		    if (TREE_VALUE (spec) == new_friend)
! 		      TREE_VALUE (spec) = old_decl;
! 		}
  	      else 
  		{
  		  tree t;
  		  tree new_friend_args;
  
*************** maybe_fold_nontype_arg (tree arg)
*** 5501,5511 ****
  	  int saved_processing_template_decl = processing_template_decl; 
  	  processing_template_decl = 0;
  	  arg = tsubst_copy_and_build (arg,
  				       /*args=*/NULL_TREE,
  				       tf_error,
! 				       /*in_decl=*/NULL_TREE);
  	  processing_template_decl = saved_processing_template_decl; 
  	}
  
        arg = fold (arg);
      }
--- 5512,5523 ----
  	  int saved_processing_template_decl = processing_template_decl; 
  	  processing_template_decl = 0;
  	  arg = tsubst_copy_and_build (arg,
  				       /*args=*/NULL_TREE,
  				       tf_error,
! 				       /*in_decl=*/NULL_TREE,
! 				       /*function_p=*/false);
  	  processing_template_decl = saved_processing_template_decl; 
  	}
  
        arg = fold (arg);
      }
*************** tsubst_baselink (tree baselink, tree obj
*** 7069,7079 ****
        {
  	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) 
--- 7081,7092 ----
        {
  	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,
! 					       /*function_p=*/false);
        }
      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_qualified_id (tree qualified_id, 
*** 7110,7120 ****
    name = TREE_OPERAND (qualified_id, 1);
    if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
      {
        is_template = true;
        template_args = tsubst_copy_and_build (TREE_OPERAND (name, 1), 
! 					     args, complain, in_decl);
        name = TREE_OPERAND (name, 0);
      }
    else
      {
        is_template = false;
--- 7123,7134 ----
    name = TREE_OPERAND (qualified_id, 1);
    if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
      {
        is_template = true;
        template_args = tsubst_copy_and_build (TREE_OPERAND (name, 1), 
! 					     args, complain, in_decl,
! 					     /*function_p=*/false);
        name = TREE_OPERAND (name, 0);
      }
    else
      {
        is_template = false;
*************** tsubst_expr (tree t, tree args, tsubst_f
*** 7547,7557 ****
  
    if (processing_template_decl)
      return tsubst_copy (t, args, complain, in_decl);
  
    if (!STATEMENT_CODE_P (TREE_CODE (t)))
!     return tsubst_copy_and_build (t, args, complain, in_decl);
      
    switch (TREE_CODE (t))
      {
      case CTOR_INITIALIZER:
        prep_stmt (t);
--- 7561,7572 ----
  
    if (processing_template_decl)
      return tsubst_copy (t, args, complain, in_decl);
  
    if (!STATEMENT_CODE_P (TREE_CODE (t)))
!     return tsubst_copy_and_build (t, args, complain, in_decl,
! 				  /*function_p=*/false);
      
    switch (TREE_CODE (t))
      {
      case CTOR_INITIALIZER:
        prep_stmt (t);
*************** tsubst_expr (tree t, tree args, tsubst_f
*** 7855,7919 ****
      }
  
    return tsubst_expr (TREE_CHAIN (t), args, complain, in_decl);
  }
  
  /* Like tsubst but deals with expressions and performs semantic
!    analysis.  */
  
  tree
  tsubst_copy_and_build (tree t, 
                         tree args, 
                         tsubst_flags_t complain, 
!                        tree in_decl)
  {
    tree op1;
  
    if (t == NULL_TREE || t == error_mark_node)
      return t;
  
    switch (TREE_CODE (t))
      {
-     case IDENTIFIER_NODE:
-       if (IDENTIFIER_TYPENAME_P (t))
- 	{
- 	  tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
- 	  return do_identifier (mangle_conv_op_name_for_type (new_type),
- 				NULL_TREE);
- 	}
-       else
- 	return do_identifier (t, NULL_TREE);
- 
      case LOOKUP_EXPR:
        {
! 	if (LOOKUP_EXPR_GLOBAL (t))
! 	  {
! 	    tree token
! 	      = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
! 	    return do_scoped_id (token, IDENTIFIER_GLOBAL_VALUE (token));
! 	  }
  	else
  	  {
! 	    t = do_identifier
! 	      (tsubst_copy
! 	       (TREE_OPERAND (t, 0), args, complain, in_decl),
! 	       NULL_TREE);
! 	    if (TREE_CODE (t) == ALIAS_DECL)
! 	      t = DECL_INITIAL (t);
! 	    return t;
  	  }
        }
  
      case TEMPLATE_ID_EXPR:
        {
  	tree object;
! 	tree template
! 	  = tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, 
! 				   in_decl);
! 	tree targs
! 	  = tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain, 
! 				   in_decl);
  	
  	if (TREE_CODE (template) == COMPONENT_REF)
  	  {
  	    object = TREE_OPERAND (template, 0);
  	    template = TREE_OPERAND (template, 1);
--- 7870,7973 ----
      }
  
    return tsubst_expr (TREE_CHAIN (t), args, complain, in_decl);
  }
  
+ /* T is a postfix-expression that is not being used in a function
+    call.  Return the substituted version of T.  */
+ 
+ static tree
+ tsubst_non_call_postfix_expression (tree t, tree args, 
+ 				    tsubst_flags_t complain,
+ 				    tree in_decl)
+ {
+   if (TREE_CODE (t) == SCOPE_REF)
+     t = tsubst_qualified_id (t, args, complain, in_decl,
+ 			     /*done=*/false, /*address_p=*/false);
+   else
+     t = tsubst_copy_and_build (t, args, complain, in_decl,
+ 			       /*function_p=*/false);
+ 
+   return t;
+ }
+ 
  /* Like tsubst but deals with expressions and performs semantic
!    analysis.  FUNCTION_P is true if T is the "F" in "F (ARGS)".  */
  
  tree
  tsubst_copy_and_build (tree t, 
                         tree args, 
                         tsubst_flags_t complain, 
!                        tree in_decl,
! 		       bool function_p)
  {
+ #define RECUR(NODE) \
+   tsubst_copy_and_build (NODE, args, complain, in_decl, /*function_p=*/false)
+ 
    tree op1;
  
    if (t == NULL_TREE || t == error_mark_node)
      return t;
  
    switch (TREE_CODE (t))
      {
      case LOOKUP_EXPR:
+     case IDENTIFIER_NODE:
        {
! 	tree decl;
! 	tree scope;
! 	cp_id_kind idk;
! 	tree qualifying_class;
! 	bool non_constant_expression_p;
! 	const char *error_msg;
! 
! 	/* Remember whether this identifier was explicitly qualified
! 	   with "::".  */
! 	if (TREE_CODE (t) == LOOKUP_EXPR && LOOKUP_EXPR_GLOBAL (t))
! 	  scope = global_namespace;
  	else
+ 	  scope = NULL_TREE;
+ 	/* Get at the underlying identifier.  */
+ 	if (TREE_CODE (t) == LOOKUP_EXPR)
+ 	  t = TREE_OPERAND (t, 0);
+ 
+ 	if (IDENTIFIER_TYPENAME_P (t))
  	  {
! 	    tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
! 	    t = mangle_conv_op_name_for_type (new_type);
  	  }
+ 
+ 	/* Look up the name.  */
+ 	if (scope == global_namespace)
+ 	  decl = IDENTIFIER_GLOBAL_VALUE (t);
+ 	else
+ 	  decl = lookup_name (t, 0);
+ 
+ 	/* By convention, expressions use ERROR_MARK_NODE to indicate
+ 	   failure, not NULL_TREE.  */
+ 	if (decl == NULL_TREE)
+ 	  decl = error_mark_node;
+ 
+ 	decl = finish_id_expression (t, decl, scope,
+ 				     &idk,
+ 				     &qualifying_class,
+ 				     /*constant_expression_p=*/false,
+ 				     /*allow_non_constant_expression_p=*/false,
+ 				     &non_constant_expression_p,
+ 				     &error_msg);
+ 	if (error_msg)
+ 	  error (error_msg);
+ 	if (!function_p && TREE_CODE (decl) == IDENTIFIER_NODE)
+ 	  decl = unqualified_name_lookup_error (decl);
+ 	return decl;
        }
  
      case TEMPLATE_ID_EXPR:
        {
  	tree object;
! 	tree template = RECUR (TREE_OPERAND (t, 0));
! 	tree targs = RECUR (TREE_OPERAND (t, 1));
  	
  	if (TREE_CODE (template) == COMPONENT_REF)
  	  {
  	    object = TREE_OPERAND (template, 0);
  	    template = TREE_OPERAND (template, 1);
*************** tsubst_copy_and_build (tree t, 
*** 7928,7977 ****
  	else
  	  return template;
        }
  
      case INDIRECT_REF:
!       return build_x_indirect_ref
! 	(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl),
! 	 "unary *");
  
      case CAST_EXPR:
        return build_functional_cast
  	(tsubst (TREE_TYPE (t), args, complain, in_decl),
! 	 tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
  
      case REINTERPRET_CAST_EXPR:
        return build_reinterpret_cast
  	(tsubst (TREE_TYPE (t), args, complain, in_decl),
! 	 tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
  
      case CONST_CAST_EXPR:
        return build_const_cast
  	(tsubst (TREE_TYPE (t), args, complain, in_decl),
! 	 tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
  
      case DYNAMIC_CAST_EXPR:
        return build_dynamic_cast
  	(tsubst (TREE_TYPE (t), args, complain, in_decl),
! 	 tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
  
      case STATIC_CAST_EXPR:
        return build_static_cast
  	(tsubst (TREE_TYPE (t), args, complain, in_decl),
! 	 tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
  
      case POSTDECREMENT_EXPR:
      case POSTINCREMENT_EXPR:
!       op1 = TREE_OPERAND (t, 0);
!       if (TREE_CODE (op1) == SCOPE_REF)
! 	op1 = tsubst_qualified_id (TREE_OPERAND (t, 0),
! 				   args, complain, 
! 				   in_decl,
! 				   /*done=*/false,
! 				   /*address_p=*/false);
!       else
! 	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:
--- 7982,8022 ----
  	else
  	  return template;
        }
  
      case INDIRECT_REF:
!       return build_x_indirect_ref (RECUR (TREE_OPERAND (t, 0)), "unary *");
  
      case CAST_EXPR:
        return build_functional_cast
  	(tsubst (TREE_TYPE (t), args, complain, in_decl),
! 	 RECUR (TREE_OPERAND (t, 0)));
  
      case REINTERPRET_CAST_EXPR:
        return build_reinterpret_cast
  	(tsubst (TREE_TYPE (t), args, complain, in_decl),
! 	 RECUR (TREE_OPERAND (t, 0)));
  
      case CONST_CAST_EXPR:
        return build_const_cast
  	(tsubst (TREE_TYPE (t), args, complain, in_decl),
! 	 RECUR (TREE_OPERAND (t, 0)));
  
      case DYNAMIC_CAST_EXPR:
        return build_dynamic_cast
  	(tsubst (TREE_TYPE (t), args, complain, in_decl),
! 	 RECUR (TREE_OPERAND (t, 0)));
  
      case STATIC_CAST_EXPR:
        return build_static_cast
  	(tsubst (TREE_TYPE (t), args, complain, in_decl),
! 	 RECUR (TREE_OPERAND (t, 0)));
  
      case POSTDECREMENT_EXPR:
      case POSTINCREMENT_EXPR:
!       op1 = tsubst_non_call_postfix_expression (TREE_OPERAND (t, 0),
! 						args, complain, in_decl);
        return build_x_unary_op (TREE_CODE (t), op1);
  
      case PREDECREMENT_EXPR:
      case PREINCREMENT_EXPR:
      case NEGATE_EXPR:
*************** tsubst_copy_and_build (tree t, 
*** 7979,8000 ****
      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:
--- 8024,8043 ----
      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), RECUR (TREE_OPERAND (t, 0)));
  
      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_non_call_postfix_expression (op1, args, complain, 
! 						  in_decl);
        return build_x_unary_op (ADDR_EXPR, op1);
  
      case PLUS_EXPR:
      case MINUS_EXPR:
      case MULT_EXPR:
*************** tsubst_copy_and_build (tree t, 
*** 8024,8069 ****
      case LE_EXPR:
      case GE_EXPR:
      case LT_EXPR:
      case GT_EXPR:
      case MEMBER_REF:
        return build_x_binary_op
  	(TREE_CODE (t), 
! 	 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 DOTSTAR_EXPR:
!       return build_m_component_ref
! 	(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 SCOPE_REF:
        return tsubst_qualified_id (t, args, complain, in_decl, /*done=*/true,
  				  /*address_p=*/false);
  
      case ARRAY_REF:
        if (tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl)
  	  == NULL_TREE)
  	/* new-type-id */
! 	return build_nt
! 	  (ARRAY_REF, NULL_TREE,
! 	   tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain,
! 				  in_decl));
  
!       op1 = TREE_OPERAND (t, 0);
!       if (TREE_CODE (op1) == SCOPE_REF)
! 	op1 = tsubst_qualified_id (op1, args, complain, in_decl,
! 				   /*done=*/false, /*address_p=*/false);
!       else
! 	op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
        /* Remember that there was a reference to this entity.  */
        if (DECL_P (op1))
  	mark_used (op1);
!       return grok_array_decl (op1, 
! 			      tsubst_copy_and_build (TREE_OPERAND (t, 1), 
! 						     args, complain,
! 						     in_decl));
  
      case SIZEOF_EXPR:
      case ALIGNOF_EXPR:
        op1 = TREE_OPERAND (t, 0);
        if (!args)
--- 8067,8098 ----
      case LE_EXPR:
      case GE_EXPR:
      case LT_EXPR:
      case GT_EXPR:
      case MEMBER_REF:
+     case DOTSTAR_EXPR:
        return build_x_binary_op
  	(TREE_CODE (t), 
! 	 RECUR (TREE_OPERAND (t, 0)),
! 	 RECUR (TREE_OPERAND (t, 1)));
  
      case SCOPE_REF:
        return tsubst_qualified_id (t, args, complain, in_decl, /*done=*/true,
  				  /*address_p=*/false);
  
      case ARRAY_REF:
        if (tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl)
  	  == NULL_TREE)
  	/* new-type-id */
! 	return build_nt (ARRAY_REF, NULL_TREE, RECUR (TREE_OPERAND (t, 1)));
  
!       op1 = tsubst_non_call_postfix_expression (TREE_OPERAND (t, 0),
! 						args, complain, in_decl);
        /* Remember that there was a reference to this entity.  */
        if (DECL_P (op1))
  	mark_used (op1);
!       return grok_array_decl (op1, RECUR (TREE_OPERAND (t, 1)));
  
      case SIZEOF_EXPR:
      case ALIGNOF_EXPR:
        op1 = TREE_OPERAND (t, 0);
        if (!args)
*************** tsubst_copy_and_build (tree t, 
*** 8075,8144 ****
  	    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_OPERAND (t, 2), args, complain, in_decl));
  
      case ARROW_EXPR:
!       op1 = TREE_OPERAND (t, 0);
!       if (TREE_CODE (op1) == SCOPE_REF)
! 	op1 = tsubst_qualified_id (op1, args, complain, in_decl,
! 				   /*done=*/false, /*address_p=*/false);
!       else
! 	op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
        /* Remember that there was a reference to this entity.  */
        if (DECL_P (op1))
  	mark_used (op1);
        return build_x_arrow (op1);
  
      case NEW_EXPR:
        return build_new
! 	(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl),
! 	 tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain, in_decl),
! 	 tsubst_copy_and_build (TREE_OPERAND (t, 2), args, complain, in_decl),
  	 NEW_EXPR_USE_GLOBAL (t));
  
      case DELETE_EXPR:
       return delete_sanity
!        (tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl),
! 	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;
- 	tree koenig_name;
  	bool qualified_p;
  
  	function = TREE_OPERAND (t, 0);
- 	if (TREE_CODE (function) == LOOKUP_EXPR
- 	    && !LOOKUP_EXPR_GLOBAL (function))
- 	  koenig_name = TREE_OPERAND (function, 0);
- 	else
- 	  koenig_name = NULL_TREE;
  	if (TREE_CODE (function) == SCOPE_REF)
  	  {
  	    qualified_p = true;
  	    function = tsubst_qualified_id (function, args, complain, in_decl,
  					    /*done=*/false, 
--- 8104,8160 ----
  	    op1 = TREE_TYPE (op1);
  	}
        else
  	{
  	  ++skip_evaluation;
! 	  op1 = RECUR (op1);
  	  --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
! 	(RECUR (TREE_OPERAND (t, 0)),
  	 TREE_CODE (TREE_OPERAND (t, 1)),
! 	 RECUR (TREE_OPERAND (t, 2)));
  
      case ARROW_EXPR:
!       op1 = tsubst_non_call_postfix_expression (TREE_OPERAND (t, 0),
! 						args, complain, in_decl);
        /* Remember that there was a reference to this entity.  */
        if (DECL_P (op1))
  	mark_used (op1);
        return build_x_arrow (op1);
  
      case NEW_EXPR:
        return build_new
! 	(RECUR (TREE_OPERAND (t, 0)),
! 	 RECUR (TREE_OPERAND (t, 1)),
! 	 RECUR (TREE_OPERAND (t, 2)),
  	 NEW_EXPR_USE_GLOBAL (t));
  
      case DELETE_EXPR:
       return delete_sanity
!        (RECUR (TREE_OPERAND (t, 0)),
! 	RECUR (TREE_OPERAND (t, 1)),
  	DELETE_EXPR_USE_VEC (t),
  	DELETE_EXPR_USE_GLOBAL (t));
  
      case COMPOUND_EXPR:
!       return build_x_compound_expr (RECUR (TREE_OPERAND (t, 0)),
! 				    RECUR (TREE_OPERAND (t, 1)));
  
      case CALL_EXPR:
        {
  	tree function;
  	tree call_args;
  	bool qualified_p;
  
  	function = TREE_OPERAND (t, 0);
  	if (TREE_CODE (function) == SCOPE_REF)
  	  {
  	    qualified_p = true;
  	    function = tsubst_qualified_id (function, args, complain, in_decl,
  					    /*done=*/false, 
*************** tsubst_copy_and_build (tree t, 
*** 8148,8175 ****
  	  {
  	    qualified_p = (TREE_CODE (function) == COMPONENT_REF
  			   && (TREE_CODE (TREE_OPERAND (function, 1))
  			       == SCOPE_REF));
  	    function = tsubst_copy_and_build (function, args, complain, 
! 					      in_decl);
! 	    function = convert_from_reference (function);
  	  }
  
! 	/* Remember that there was a reference to this entity.  */
! 	if (DECL_P (function))
! 	  mark_used (function);
! 
! 	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 
--- 8164,8199 ----
  	  {
  	    qualified_p = (TREE_CODE (function) == COMPONENT_REF
  			   && (TREE_CODE (TREE_OPERAND (function, 1))
  			       == SCOPE_REF));
  	    function = tsubst_copy_and_build (function, args, complain, 
! 					      in_decl,
! 					      !qualified_p);
  	  }
  
! 	call_args = RECUR (TREE_OPERAND (t, 1));
  	  
  	if (BASELINK_P (function))
  	  qualified_p = 1;
  
! 	if (!qualified_p
! 	    && TREE_CODE (function) != TEMPLATE_ID_EXPR
! 	    && (is_overloaded_fn (function)
! 		|| DECL_P (function)
! 		|| TREE_CODE (function) == IDENTIFIER_NODE))
! 	  {
! 	    if (call_args)
! 	      function = perform_koenig_lookup (function, call_args);
! 	    else if (TREE_CODE (function) == IDENTIFIER_NODE)
! 	      function = unqualified_name_lookup_error (function);
! 	  }
! 
! 	/* Remember that there was a reference to this entity.  */
! 	if (DECL_P (function))
! 	  mark_used (function);
! 
! 	function = convert_from_reference (function);
  
  	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 
*************** tsubst_copy_and_build (tree t, 
*** 8181,8216 ****
  				 /*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_OPERAND (t, 1), args, complain, in_decl),
! 	 tsubst_copy_and_build (TREE_OPERAND (t, 2), args, complain, in_decl));
  
      case PSEUDO_DTOR_EXPR:
        return finish_pseudo_destructor_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),
! 	 tsubst_copy_and_build (TREE_OPERAND (t, 2), args, complain, in_decl));
  
      case TREE_LIST:
        {
  	tree purpose, value, chain;
  
  	if (t == void_list_node)
  	  return t;
  
  	purpose = TREE_PURPOSE (t);
  	if (purpose)
! 	  purpose = tsubst_copy_and_build (purpose, args, complain, in_decl);
  	value = TREE_VALUE (t);
  	if (value)
! 	  value = tsubst_copy_and_build (value, args, complain, in_decl);
  	chain = TREE_CHAIN (t);
  	if (chain && chain != void_type_node)
! 	  chain = tsubst_copy_and_build (chain, args, complain, in_decl);
  	if (purpose == TREE_PURPOSE (t)
  	    && value == TREE_VALUE (t)
  	    && chain == TREE_CHAIN (t))
  	  return t;
  	return tree_cons (purpose, value, chain);
--- 8205,8240 ----
  				 /*disallow_virtual=*/qualified_p);
        }
  
      case COND_EXPR:
        return build_x_conditional_expr
! 	(RECUR (TREE_OPERAND (t, 0)),
! 	 RECUR (TREE_OPERAND (t, 1)),
! 	 RECUR (TREE_OPERAND (t, 2)));
  
      case PSEUDO_DTOR_EXPR:
        return finish_pseudo_destructor_expr 
! 	(RECUR (TREE_OPERAND (t, 0)),
! 	 RECUR (TREE_OPERAND (t, 1)),
! 	 RECUR (TREE_OPERAND (t, 2)));
  
      case TREE_LIST:
        {
  	tree purpose, value, chain;
  
  	if (t == void_list_node)
  	  return t;
  
  	purpose = TREE_PURPOSE (t);
  	if (purpose)
! 	  purpose = RECUR (purpose);
  	value = TREE_VALUE (t);
  	if (value)
! 	  value = RECUR (value);
  	chain = TREE_CHAIN (t);
  	if (chain && chain != void_type_node)
! 	  chain = RECUR (chain);
  	if (purpose == TREE_PURPOSE (t)
  	    && value == TREE_VALUE (t)
  	    && chain == TREE_CHAIN (t))
  	  return t;
  	return tree_cons (purpose, value, chain);
*************** tsubst_copy_and_build (tree t, 
*** 8219,8235 ****
      case COMPONENT_REF:
        {
  	tree object;
  	tree member;
  
! 	object = TREE_OPERAND (t, 0);
! 	if (TREE_CODE (object) == SCOPE_REF)
! 	  object = tsubst_qualified_id (object, args, complain, in_decl,
! 					/*done=*/false, /*address_p=*/false);
! 	else
! 	  object = tsubst_copy_and_build (object, args, complain, in_decl);
! 
  	/* Remember that there was a reference to this entity.  */
  	if (DECL_P (object))
  	  mark_used (object);
  
  	member = TREE_OPERAND (t, 1);
--- 8243,8254 ----
      case COMPONENT_REF:
        {
  	tree object;
  	tree member;
  
! 	object = tsubst_non_call_postfix_expression (TREE_OPERAND (t, 0),
! 						     args, complain, in_decl);
  	/* Remember that there was a reference to this entity.  */
  	if (DECL_P (object))
  	  mark_used (object);
  
  	member = TREE_OPERAND (t, 1);
*************** tsubst_copy_and_build (tree t, 
*** 8280,8290 ****
  	return finish_class_member_access_expr (object, member);
        }
  
      case THROW_EXPR:
        return build_throw
! 	(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
  
      case CONSTRUCTOR:
        {
  	tree r;
  	tree elts;
--- 8299,8309 ----
  	return finish_class_member_access_expr (object, member);
        }
  
      case THROW_EXPR:
        return build_throw
! 	(RECUR (TREE_OPERAND (t, 0)));
  
      case CONSTRUCTOR:
        {
  	tree r;
  	tree elts;
*************** tsubst_copy_and_build (tree t, 
*** 8306,8318 ****
  	  {
  	    tree purpose = TREE_PURPOSE (elts);
  	    tree value = TREE_VALUE (elts);
  	    
  	    if (purpose && purpose_p)
! 	      purpose
! 		= tsubst_copy_and_build (purpose, args, complain, in_decl);
! 	    value = tsubst_copy_and_build (value, args, complain, in_decl);
  	    r = tree_cons (purpose, value, r);
  	  }
  	
  	r = build_constructor (NULL_TREE, nreverse (r));
  	TREE_HAS_CONSTRUCTOR (r) = TREE_HAS_CONSTRUCTOR (t);
--- 8325,8336 ----
  	  {
  	    tree purpose = TREE_PURPOSE (elts);
  	    tree value = TREE_VALUE (elts);
  	    
  	    if (purpose && purpose_p)
! 	      purpose = RECUR (purpose);
! 	    value = RECUR (value);
  	    r = tree_cons (purpose, value, r);
  	  }
  	
  	r = build_constructor (NULL_TREE, nreverse (r));
  	TREE_HAS_CONSTRUCTOR (r) = TREE_HAS_CONSTRUCTOR (t);
*************** tsubst_copy_and_build (tree t, 
*** 8322,8335 ****
  	return r;
        }
  
      case TYPEID_EXPR:
        {
! 	tree operand_0
! 	  = tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
! 				   in_decl);
! 	
  	if (TYPE_P (operand_0))
  	  return get_typeid (operand_0);
  	return build_typeid (operand_0);
        }
  
--- 8340,8350 ----
  	return r;
        }
  
      case TYPEID_EXPR:
        {
! 	tree operand_0 = RECUR (TREE_OPERAND (t, 0));
  	if (TYPE_P (operand_0))
  	  return get_typeid (operand_0);
  	return build_typeid (operand_0);
        }
  
*************** tsubst_copy_and_build (tree t, 
*** 8345,8362 ****
  	   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
! 	   (TREE_OPERAND (t, 0), args, complain, in_decl),
! 	   tsubst_copy (TREE_TYPE (t), args, complain, in_decl));
  
      default:
        return tsubst_copy (t, args, complain, in_decl);
      }
  }
  
  /* Verify that the instantiated ARGS are valid. For type arguments,
     make sure that the type's linkage is ok. For non-type arguments,
     make sure they are constants if they are integral or enumerations.
--- 8360,8378 ----
  	   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 (RECUR (TREE_OPERAND (t, 0)),
! 			     tsubst_copy (TREE_TYPE (t), args, complain, 
! 					  in_decl));
  
      default:
        return tsubst_copy (t, args, complain, in_decl);
      }
+ 
+ #undef RECUR
  }
  
  /* Verify that the instantiated ARGS are valid. For type arguments,
     make sure that the type's linkage is ok. For non-type arguments,
     make sure they are constants if they are integral or enumerations.
*************** regenerate_decl_from_template (tree decl
*** 10574,10595 ****
    /* The arguments used to instantiate DECL, from the most general
       template.  */
    tree args;
    tree code_pattern;
    tree new_decl;
!   int unregistered;
  
    args = DECL_TI_ARGS (decl);
    code_pattern = DECL_TEMPLATE_RESULT (tmpl);
  
    /* Unregister the specialization so that when we tsubst we will not
       just return DECL.  We don't have to unregister DECL from TMPL
       because if would only be registered there if it were a partial
       instantiation of a specialization, which it isn't: it's a full
       instantiation.  */
    gen_tmpl = most_general_template (tmpl);
!   unregistered = unregister_specialization (decl, gen_tmpl);
  
    /* If the DECL was not unregistered then something peculiar is
       happening: we created a specialization but did not call
       register_specialization for it.  */
    my_friendly_assert (unregistered, 0);
--- 10590,10612 ----
    /* The arguments used to instantiate DECL, from the most general
       template.  */
    tree args;
    tree code_pattern;
    tree new_decl;
!   bool unregistered;
  
    args = DECL_TI_ARGS (decl);
    code_pattern = DECL_TEMPLATE_RESULT (tmpl);
  
    /* Unregister the specialization so that when we tsubst we will not
       just return DECL.  We don't have to unregister DECL from TMPL
       because if would only be registered there if it were a partial
       instantiation of a specialization, which it isn't: it's a full
       instantiation.  */
    gen_tmpl = most_general_template (tmpl);
!   unregistered = reregister_specialization (decl, gen_tmpl,
! 					    /*new_spec=*/NULL_TREE);
  
    /* If the DECL was not unregistered then something peculiar is
       happening: we created a specialization but did not call
       register_specialization for it.  */
    my_friendly_assert (unregistered, 0);
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.325
diff -c -5 -p -r1.325 semantics.c
*** cp/semantics.c	9 Jul 2003 08:48:01 -0000	1.325
--- cp/semantics.c	14 Jul 2003 02:32:00 -0000
*************** finish_stmt_expr (tree rtl_expr)
*** 1471,1480 ****
--- 1471,1521 ----
      finish_stmt_tree (&scope_chain->x_saved_tree);
  
    return result;
  }
  
+ /* Perform Koenig lookup.  FN is the postfix-expression representing
+    the call; ARGS are the arguments to the call.  Returns the
+    functions to be considered by overload resolution.  */
+ 
+ tree
+ perform_koenig_lookup (tree fn, tree args)
+ {
+   tree identifier = NULL_TREE;
+   tree functions = NULL_TREE;
+ 
+   /* Find the name of the overloaded function.  */
+   if (TREE_CODE (fn) == IDENTIFIER_NODE)
+     identifier = fn;
+   else if (is_overloaded_fn (fn))
+     {
+       functions = fn;
+       identifier = DECL_NAME (get_first_fn (functions));
+     }
+   else if (DECL_P (fn))
+     {
+       functions = fn;
+       identifier = DECL_NAME (fn);
+     }
+ 
+   /* 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))
+     {
+       fn = lookup_arg_dependent (identifier, functions, args);
+       if (!fn)
+ 	/* The unqualified name could not be resolved.  */
+ 	fn = unqualified_fn_lookup_error (identifier);
+     }
+   else
+     fn = build_min_nt (LOOKUP_EXPR, identifier);
+ 
+   return fn;
+ }
+ 
  /* Generate an expression for `FN (ARGS)'.
  
     If DISALLOW_VIRTUAL is true, the call to FN will be not generated
     as a virtual call, even if FN is virtual.  (This flag is set when
     encountering an expression where the function name is explicitly
*************** check_multiple_declarators (void)
*** 2187,2196 ****
--- 2228,2537 ----
       
    if (PROCESSING_REAL_TEMPLATE_DECL_P () 
        || processing_explicit_instantiation
        || processing_specialization)
      error ("multiple declarators in template declaration");
+ }
+ 
+ /* ID_EXPRESSION is a representation of parsed, but unprocessed,
+    id-expression.  (See cp_parser_id_expression for details.)  SCOPE,
+    if non-NULL, is the type or namespace used to explicitly qualify
+    ID_EXPRESSION.  DECL is the entity to which that name has been
+    resolved.  
+ 
+    *CONSTANT_EXPRESSION_P is true if we are presently parsing a
+    constant-expression.  In that case, *NON_CONSTANT_EXPRESSION_P will
+    be set to true if this expression isn't permitted in a
+    constant-expression, but it is otherwise not set by this function.
+    *ALLOW_NON_CONSTANT_EXPRESSION_P is true if we are parsing a
+    constant-expression, but a non-constant expression is also
+    permissible.
+ 
+    If an error occurs, and it is the kind of error that might cause
+    the parser to abort a tentative parse, *ERROR_MSG is filled in.  It
+    is the caller's responsibility to issue the message.  *ERROR_MSG
+    will be a string with static storage duration, so the caller need
+    not "free" it.
+ 
+    Return an expression for the entity, after issuing appropriate
+    diagnostics.  This function is also responsible for transforming a
+    reference to a non-static member into a COMPONENT_REF that makes
+    the use of "this" explicit.  
+ 
+    Upon return, *IDK will be filled in appropriately.  */
+ 
+ tree
+ finish_id_expression (tree id_expression, 
+ 		      tree decl,
+ 		      tree scope,
+ 		      cp_id_kind *idk,
+ 		      tree *qualifying_class,
+ 		      bool constant_expression_p,
+ 		      bool allow_non_constant_expression_p,
+ 		      bool *non_constant_expression_p,
+ 		      const char **error_msg)
+ {
+   /* Initialize the output parameters.  */
+   *idk = CP_ID_KIND_NONE;
+   *error_msg = NULL;
+ 
+   if (id_expression == error_mark_node)
+     return error_mark_node;
+   /* If we have a template-id, then no further lookup is
+      required.  If the template-id was for a template-class, we
+      will sometimes have a TYPE_DECL at this point.  */
+   else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+       || TREE_CODE (decl) == TYPE_DECL)
+     ;
+   /* Look up the name.  */
+   else 
+     {
+       if (decl == error_mark_node)
+ 	{
+ 	  /* Name lookup failed.  */
+ 	  if (scope && (!TYPE_P (scope) || !dependent_type_p (scope)))
+ 	    {
+ 	      /* Qualified name lookup failed, and the qualifying name
+ 		 was not a dependent type.  That is always an
+ 		 error.  */
+ 	      if (TYPE_P (scope) && !COMPLETE_TYPE_P (scope))
+ 		error ("incomplete type `%T' used in nested name "
+ 		       "specifier",
+ 		       scope);
+ 	      else if (scope != global_namespace)
+ 		error ("`%D' is not a member of `%D'",
+ 		       id_expression, scope);
+ 	      else
+ 		error ("`::%D' has not been declared", id_expression);
+ 	      return error_mark_node;
+ 	    }
+ 	  else if (!scope)
+ 	    {
+ 	      /* It may be resolved via Koenig lookup.  */
+ 	      *idk = CP_ID_KIND_UNQUALIFIED;
+ 	      return id_expression;
+ 	    }
+ 	}
+       /* If DECL is a variable that would be out of scope under
+ 	 ANSI/ISO rules, but in scope in the ARM, name lookup
+ 	 will succeed.  Issue a diagnostic here.  */
+       else
+ 	decl = check_for_out_of_scope_variable (decl);
+ 
+       /* Remember that the name was used in the definition of
+ 	 the current class so that we can check later to see if
+ 	 the meaning would have been different after the class
+ 	 was entirely defined.  */
+       if (!scope && decl != error_mark_node)
+ 	maybe_note_name_used_in_class (id_expression, decl);
+     }
+ 
+   /* If we didn't find anything, or what we found was a type,
+      then this wasn't really an id-expression.  */
+   if (TREE_CODE (decl) == TEMPLATE_DECL
+       && !DECL_FUNCTION_TEMPLATE_P (decl))
+     {
+       *error_msg = "missing template arguments";
+       return error_mark_node;
+     }
+   else if (TREE_CODE (decl) == TYPE_DECL
+ 	   || TREE_CODE (decl) == NAMESPACE_DECL)
+     {
+       *error_msg = "expected primary-expression";
+       return error_mark_node;
+     }
+ 
+   /* If the name resolved to a template parameter, there is no
+      need to look it up again later.  Similarly, we resolve
+      enumeration constants to their underlying values.  */
+   if (TREE_CODE (decl) == CONST_DECL)
+     {
+       *idk = CP_ID_KIND_NONE;
+       if (DECL_TEMPLATE_PARM_P (decl) || !processing_template_decl)
+ 	return DECL_INITIAL (decl);
+       return decl;
+     }
+   else
+     {
+       bool dependent_p;
+ 
+       /* If the declaration was explicitly qualified indicate
+ 	 that.  The semantics of `A::f(3)' are different than
+ 	 `f(3)' if `f' is virtual.  */
+       *idk = (scope 
+ 	      ? CP_ID_KIND_QUALIFIED
+ 	      : (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+ 		 ? CP_ID_KIND_TEMPLATE_ID
+ 		 : CP_ID_KIND_UNQUALIFIED));
+ 
+ 
+       /* [temp.dep.expr]
+ 
+ 	 An id-expression is type-dependent if it contains an
+ 	 identifier that was declared with a dependent type.
+ 
+ 	 As an optimization, we could choose not to create a
+ 	 LOOKUP_EXPR for a name that resolved to a local variable in
+ 	 the template function that we are currently declaring; such a
+ 	 name cannot ever resolve to anything else.  If we did that we
+ 	 would not have to look up these names at instantiation time.
+ 
+ 	 The standard is not very specific about an id-expression that
+ 	 names a set of overloaded functions.  What if some of them
+ 	 have dependent types and some of them do not?  Presumably,
+ 	 such a name should be treated as a dependent name.  */
+       /* Assume the name is not dependent.  */
+       dependent_p = false;
+       if (!processing_template_decl)
+ 	/* No names are dependent outside a template.  */
+ 	;
+       /* A template-id where the name of the template was not resolved
+ 	 is definitely dependent.  */
+       else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+ 	       && (TREE_CODE (TREE_OPERAND (decl, 0)) 
+ 		   == IDENTIFIER_NODE))
+ 	dependent_p = true;
+       /* For anything except an overloaded function, just check its
+ 	 type.  */
+       else if (!is_overloaded_fn (decl))
+ 	dependent_p 
+ 	  = dependent_type_p (TREE_TYPE (decl));
+       /* For a set of overloaded functions, check each of the
+ 	 functions.  */
+       else
+ 	{
+ 	  tree fns = decl;
+ 
+ 	  if (BASELINK_P (fns))
+ 	    fns = BASELINK_FUNCTIONS (fns);
+ 
+ 	  /* 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);
+ 	    }
+ 
+ 	  /* If there are no dependent template arguments, go through
+ 	     the overlaoded functions.  */
+ 	  while (fns && !dependent_p)
+ 	    {
+ 	      tree fn = OVL_CURRENT (fns);
+ 
+ 	      /* Member functions of dependent classes are
+ 		 dependent.  */
+ 	      if (TREE_CODE (fn) == FUNCTION_DECL
+ 		  && type_dependent_expression_p (fn))
+ 		dependent_p = true;
+ 	      else if (TREE_CODE (fn) == TEMPLATE_DECL
+ 		       && dependent_template_p (fn))
+ 		dependent_p = true;
+ 
+ 	      fns = OVL_NEXT (fns);
+ 	    }
+ 	}
+ 
+       /* If the name was dependent on a template parameter, we will
+ 	 resolve the name at instantiation time.  */
+       if (dependent_p)
+ 	{
+ 	  /* Create a SCOPE_REF for qualified names, if the scope is
+ 	     dependent.  */
+ 	  if (scope)
+ 	    {
+ 	      if (TYPE_P (scope))
+ 		*qualifying_class = scope;
+ 	      /* Since this name was dependent, the expression isn't
+ 		 constant -- yet.  No error is issued because it might
+ 		 be constant when things are instantiated.  */
+ 	      if (constant_expression_p)
+ 		*non_constant_expression_p = true;
+ 	      if (TYPE_P (scope) && dependent_type_p (scope))
+ 		return build_nt (SCOPE_REF, scope, id_expression);
+ 	      else if (TYPE_P (scope) && DECL_P (decl))
+ 		return build (SCOPE_REF, TREE_TYPE (decl), scope,
+ 			      id_expression);
+ 	      else
+ 		return decl;
+ 	    }
+ 	  /* A TEMPLATE_ID already contains all the information we
+ 	     need.  */
+ 	  if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR)
+ 	    return id_expression;
+ 	  /* Since this name was dependent, the expression isn't
+ 	     constant -- yet.  No error is issued because it might be
+ 	     constant when things are instantiated.  */
+ 	  if (constant_expression_p)
+ 	    *non_constant_expression_p = true;
+ 	  /* Create a LOOKUP_EXPR for other unqualified names.  */
+ 	  return build_min_nt (LOOKUP_EXPR, id_expression);
+ 	}
+ 
+       /* Only certain kinds of names are allowed in constant
+ 	 expression.  Enumerators have already been handled above.  */
+       if (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 (!allow_non_constant_expression_p)
+ 		{
+ 		  error ("`%D' cannot appear in a constant-expression", decl);
+ 		  return error_mark_node;
+ 		}
+ 	      *non_constant_expression_p = true;
+ 	    }
+ 	}
+ 
+       if (scope)
+ 	{
+ 	  decl = (adjust_result_of_qualified_name_lookup 
+ 		  (decl, scope, current_class_type));
+ 	  if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (decl))
+ 	    *qualifying_class = scope;
+ 	  else if (!processing_template_decl)
+ 	    decl = convert_from_reference (decl);
+ 	  else if (TYPE_P (scope))
+ 	    decl = build (SCOPE_REF, TREE_TYPE (decl), scope, decl);
+ 	}
+       else
+ 	/* Transform references to non-static data members into
+ 	   COMPONENT_REFs.  */
+ 	decl = hack_identifier (decl, id_expression);
+ 
+       /* Resolve references to variables of anonymous unions
+ 	 into COMPONENT_REFs.  */
+       if (TREE_CODE (decl) == ALIAS_DECL)
+ 	decl = DECL_INITIAL (decl);
+     }
+ 
+   if (TREE_DEPRECATED (decl))
+     warn_deprecated_use (decl);
+ 
+   return decl;
  }
  
  /* Implement the __typeof keyword: Return the type of EXPR, suitable for
     use as a type-specifier.  */
  
Index: testsuite/g++.dg/template/crash4.C
===================================================================
RCS file: testsuite/g++.dg/template/crash4.C
diff -N testsuite/g++.dg/template/crash4.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/crash4.C	14 Jul 2003 02:32:03 -0000
***************
*** 0 ****
--- 1,12 ----
+ namespace NS {
+     struct C {};
+     void foo();
+ }
+ 
+ template <class T> struct X {};
+ 
+ template <class T> struct A {
+     A() { foo (X<T>()); }
+     void foo(X<T>);
+ };
+ template struct A<NS::C>;
Index: testsuite/g++.dg/template/koenig1.C
===================================================================
RCS file: testsuite/g++.dg/template/koenig1.C
diff -N testsuite/g++.dg/template/koenig1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/koenig1.C	14 Jul 2003 02:32:03 -0000
***************
*** 0 ****
--- 1,8 ----
+ namespace NS {
+     struct C {};
+     void foo(C);
+ }
+ 
+ template <class T> void bar() { T t; foo (t); }
+ 
+ template void bar<NS::C> ();
Index: testsuite/g++.old-deja/g++.benjamin/tem03.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.benjamin/tem03.C,v
retrieving revision 1.8
diff -c -5 -p -r1.8 tem03.C
*** testsuite/g++.old-deja/g++.benjamin/tem03.C	1 May 2003 02:02:33 -0000	1.8
--- testsuite/g++.old-deja/g++.benjamin/tem03.C	14 Jul 2003 02:32:03 -0000
*************** struct Xthirteen {
*** 193,203 ****
    template <long l> long comp_ge(long test) {// { dg-error "" } .
      long local_value;
      if (local_value > value) // { dg-error "" } .*
        return local_value;
      else
!       return value; // { dg-error "" } .*
    }
  };
  
  
  
--- 193,203 ----
    template <long l> long comp_ge(long test) {// { dg-error "" } .
      long local_value;
      if (local_value > value) // { dg-error "" } .*
        return local_value;
      else
!       return value;
    }
  };
  
  
  
Index: testsuite/g++.old-deja/g++.benjamin/tem06.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.benjamin/tem06.C,v
retrieving revision 1.5
diff -c -5 -p -r1.5 tem06.C
*** testsuite/g++.old-deja/g++.benjamin/tem06.C	1 May 2003 02:02:33 -0000	1.5
--- testsuite/g++.old-deja/g++.benjamin/tem06.C	14 Jul 2003 02:32:03 -0000
*************** class foo {
*** 12,21 ****
--- 12,23 ----
  public:
    foo () {}
    friend void x (const T &) { }
  };
  
+ void x(const int &);
+ 
  template<class T>
  void blah (const T &) {
    T y;
    x (4);
  }
Index: testsuite/g++.old-deja/g++.jason/overload33.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.jason/overload33.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 overload33.C
*** testsuite/g++.old-deja/g++.jason/overload33.C	1 May 2003 02:02:40 -0000	1.3
--- testsuite/g++.old-deja/g++.jason/overload33.C	14 Jul 2003 02:32:04 -0000
*************** class SmartPtr : public ConstSmartPtr<T>
*** 56,69 ****
    public:
  			SmartPtr(T* theItem)
  			  : ConstSmartPtr<T>(theItem) {}
  
      T*			item() const
! 				{ return _item(); }
  
  			operator T*() const
! 				{ return _item(); }
  };
  
  /* ------------------------------------------------------------ */
  
  void
--- 56,69 ----
    public:
  			SmartPtr(T* theItem)
  			  : ConstSmartPtr<T>(theItem) {}
  
      T*			item() const
! 				{ return this->_item(); }
  
  			operator T*() const
! 				{ return this->_item(); }
  };
  
  /* ------------------------------------------------------------ */
  
  void
Index: testsuite/g++.old-deja/g++.jason/template36.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.jason/template36.C,v
retrieving revision 1.4
diff -c -5 -p -r1.4 template36.C
*** testsuite/g++.old-deja/g++.jason/template36.C	1 May 2003 02:02:41 -0000	1.4
--- testsuite/g++.old-deja/g++.jason/template36.C	14 Jul 2003 02:32:04 -0000
*************** public:
*** 31,41 ****
  
      base f ();
      int base::* g ();
  
      int zowee() const
!     { return bar(); }  
  };
  
  template <class T>
  typename weird<T>::base weird<T>::f ()
  {
--- 31,41 ----
  
      base f ();
      int base::* g ();
  
      int zowee() const
!     { return this->bar(); }  
  };
  
  template <class T>
  typename weird<T>::base weird<T>::f ()
  {
Index: testsuite/g++.old-deja/g++.mike/p1989.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.mike/p1989.C,v
retrieving revision 1.6
diff -c -5 -p -r1.6 p1989.C
*** testsuite/g++.old-deja/g++.mike/p1989.C	1 May 2003 02:02:45 -0000	1.6
--- testsuite/g++.old-deja/g++.mike/p1989.C	14 Jul 2003 02:32:05 -0000
*************** public:
*** 193,204 ****
  
  template<class T>
  Pix
  List_DLS<T>::search(const T& item) const
  {
!     for (Pix x=first(); 0 != x; next(x)) {
! 	if (item == operator()(x)) // { dg-error "" } const subversion
  	    return x;
      }
      return 0;
  }
  
--- 193,204 ----
  
  template<class T>
  Pix
  List_DLS<T>::search(const T& item) const
  {
!     for (Pix x=this->first(); 0 != x; this->next(x)) {
! 	if (item == this->operator()(x)) // { dg-error "" } const subversion
  	    return x;
      }
      return 0;
  }
  
*************** public:
*** 221,232 ****
  
  template<class T>
  bool
  List_DLSp<T>::contains(const T& item) const
  {
!     for (Pix x=first(); 0 != x; next(x)) {
! 	if (*item == *operator()(x))
  	    return TRUE;
      }
      return FALSE;
  }
  
--- 221,232 ----
  
  template<class T>
  bool
  List_DLSp<T>::contains(const T& item) const
  {
!     for (Pix x=this->first(); 0 != x; this->next(x)) {
!         if (*item == *(this->operator()(x)))
  	    return TRUE;
      }
      return FALSE;
  }
  
Index: testsuite/g++.old-deja/g++.pt/lookup2.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.pt/lookup2.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 lookup2.C
*** testsuite/g++.old-deja/g++.pt/lookup2.C	1 May 2003 02:02:54 -0000	1.3
--- testsuite/g++.old-deja/g++.pt/lookup2.C	14 Jul 2003 02:32:06 -0000
***************
*** 1,7 ****
  // { dg-do assemble  }
! // { dg-options "" }
  
  class A
  {
  protected:
    void f1() {};
--- 1,7 ----
  // { dg-do assemble  }
! // { dg-options "-fpermissive" }
  
  class A
  {
  protected:
    void f1() {};
*************** protected:
*** 13,20 ****
  };
  
  template <class T> class D : private B<T>
  {
  public:
!   void f2() { f1(); };
  };
  
--- 13,20 ----
  };
  
  template <class T> class D : private B<T>
  {
  public:
!   void f2() { f1(); }; // { dg-warning "" }
  };
  
Index: testsuite/g++.old-deja/g++.pt/ttp20.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.pt/ttp20.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 ttp20.C
*** testsuite/g++.old-deja/g++.pt/ttp20.C	1 May 2003 02:02:56 -0000	1.3
--- testsuite/g++.old-deja/g++.pt/ttp20.C	14 Jul 2003 02:32:06 -0000
*************** template<template<class> class D,class E
*** 16,26 ****
  		int g();
  };
  
  template<template<class> class D,class E> int C<D,E>::g()
  {
! 	return f();
  }
  
  int main()
  {
  	C<D,int> c;
--- 16,26 ----
  		int g();
  };
  
  template<template<class> class D,class E> int C<D,E>::g()
  {
! 	return this->f();
  }
  
  int main()
  {
  	C<D,int> c;
Index: testsuite/g++.old-deja/g++.pt/ttp21.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.pt/ttp21.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 ttp21.C
*** testsuite/g++.old-deja/g++.pt/ttp21.C	1 May 2003 02:02:56 -0000	1.3
--- testsuite/g++.old-deja/g++.pt/ttp21.C	14 Jul 2003 02:32:06 -0000
*************** template<template<class> class D,class E
*** 16,32 ****
  		int g();
  };
  
  template<template<class> class D,class E> int C<D,E>::g()
  {
! 	return f();
  }
  
  class E : C<D,int>
  {
  	public:
! 		int h() { return g(); }
  };
  
  int main()
  {
  	E c;
--- 16,32 ----
  		int g();
  };
  
  template<template<class> class D,class E> int C<D,E>::g()
  {
! 	return this->f();
  }
  
  class E : C<D,int>
  {
  	public:
! 		int h() { return this->g(); }
  };
  
  int main()
  {
  	E c;
Index: testsuite/g++.old-deja/g++.pt/typename13.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.pt/typename13.C,v
retrieving revision 1.4
diff -c -5 -p -r1.4 typename13.C
*** testsuite/g++.old-deja/g++.pt/typename13.C	1 May 2003 02:02:56 -0000	1.4
--- testsuite/g++.old-deja/g++.pt/typename13.C	14 Jul 2003 02:32:06 -0000
***************
*** 1,7 ****
  // { dg-do assemble  }
! // { dg-options "" }
  
  template <class T>
  struct B 
  {
    typedef int I;
--- 1,7 ----
  // { dg-do assemble  }
! // { dg-options "-fpermissive" }
  
  template <class T>
  struct B 
  {
    typedef int I;
*************** struct D : public B<T>
*** 16,26 ****
  
  
  template <class T>
  void D<T>::f()
  {
!   I();
  }
  
  
  template <>
  struct B<int> 
--- 16,26 ----
  
  
  template <class T>
  void D<T>::f()
  {
!   I(); // { dg-warning "" }
  }
  
  
  template <>
  struct B<int> 
Index: testsuite/g++.old-deja/g++.pt/union2.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.pt/union2.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 union2.C
*** testsuite/g++.old-deja/g++.pt/union2.C	1 May 2003 02:02:57 -0000	1.3
--- testsuite/g++.old-deja/g++.pt/union2.C	14 Jul 2003 02:32:06 -0000
*************** protected:
*** 10,18 ****
    };
    elm_t *def_basep () { return reinterpret_cast<elm_t *> (defbuf_space); }
  };
  
  template<class T> struct vector : public vector_base<T> {
!   vector () { def_basep (); }
  };
  
  vector<int> iv;
--- 10,18 ----
    };
    elm_t *def_basep () { return reinterpret_cast<elm_t *> (defbuf_space); }
  };
  
  template<class T> struct vector : public vector_base<T> {
!   vector () { this->def_basep (); }
  };
  
  vector<int> iv;
Index: testsuite/g++.dg/parse/template9.C
===================================================================
RCS file: testsuite/g++.dg/parse/template9.C
diff -N testsuite/g++.dg/parse/template9.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/parse/template9.C	14 Jul 2003 02:47:27 -0000
***************
*** 0 ****
--- 1,5 ----
+ template <typename T> 
+ void f() {
+   g(); // { dg-error "" }
+   h(3); // { dg-error "" }
+ }



More information about the Gcc-patches mailing list