From ee76b9314ba2aa2dc1f59c4efa32ac42dd84147d Mon Sep 17 00:00:00 2001
From: Mark Mitchell <mark@codesourcery.com>
Date: Tue, 8 Jul 2003 01:38:44 +0000
Subject: [PATCH] cp-tree.h (build_scoped_method_call): Remove.

	* cp-tree.h (build_scoped_method_call): Remove.
	(lookup_qualified_name): Remove parameter.
	(tsubst_copy_and_build): Declare.
	(finish_qualified_object_call_expr): Remove.
	(check_accessibility_of_qualified_id): New function.
	(finish_qualified_id_expr): Likewise.
	(non_reference): Likewise.
	(build_expr_from-tree): Remove.
	* call.c (non_reference): Remove.
	(build_scoped_method_call): Likewise.
	(build_method_call): Use error_operand_p.  Assert that we are not
	processing a template.
	(standard_conversion): Use non_reference.
	* class.c (build_vtbl_entry_ref): Likewise.
	(build_vtbl_ref_1): Likewise.
	* cvt.c (build_expr_type_conversion): Use non_reference.
	* decl.c (lookup_qualified_name): Remove flags parameter.
	(grok_op_properties): Use non_reference.
	* decl2.c (grok_array_decl): Likewise.
	(build_expr_from_tree): Remove.
	(build_offset_ref_call_from_tree): Update comment.
	* error.c (parm_to_string): Call reinit_global_formatting_buffer.
	* except.c (prepare_eh_types): Use non_reference.
	(can_convert_eh): Likewise.
	* init.c (build_dtor_call): Avoid using build_method_call.
	* mangle.c (write_template_param): Remove misleading comment.
	* method.c (locate_copy): Use non_reference.
	* parser.c (cp_parser_scope_through_which_access_occurs): Remove.
	(cp_parser_primary_expression): Do not create SCOPE_REFs is
	non-dependent contexts.
	(cp_parser_postfix_expression): Use finish_qualified_id_expr.
	(cp_parser_direct_declarator): Use tsubst_copy_and_build, not
	build_expr_from_tree.
	(cp_parser_lookup_name): Adjust call to lookup_qualified_name.
	Use check_accessibility_of_qualified_id.
	* pt.c (maybe_fold_nontype_arg): Use tsubst_copy_and_build, not
	build_expr_from_tree.
	(tsubst_baselink): New function.
	(tsubst_qualified_id): Likewise.
	(tsubst_copy): Use them.  Remove support for METHOD_CALL_EXPR.
	(tsubst_expr): Adjust call to lookup_qualified_name.
	(tsubst_copy_and_build): Handle SCOPE_REFs specially.  Adjust
	handling of CALL_EXPRs.
	(value_dependent_expression_p): Use INTEGRAL_OR_ENUMERATION_TYPE_P.
	* rtti.c (get_tinfo_decl_dynamic): Use non_reference.
	* search.c (check_final_overrider): Likewise.
	* semantics.c (check_accessibility_of_qualified_id): New function.
	(finish_qualified_object_call_expr): Remove.
	* typeck.c (target_type): Use non_reference.
	(cxx_sizeof_or_alignof_type): Likewise.
	(dubious_conversion_warnings): Likewise.
	(convert_for_initialization): Likewise.
	(non_reference): New function.

From-SVN: r69063
---
 gcc/cp/ChangeLog   |  56 ++++++
 gcc/cp/call.c      | 125 +------------
 gcc/cp/class.c     |   8 +-
 gcc/cp/cp-tree.h   |   9 +-
 gcc/cp/cvt.c       |   8 +-
 gcc/cp/decl.c      |  15 +-
 gcc/cp/decl2.c     | 426 +-------------------------------------------
 gcc/cp/error.c     |   2 +
 gcc/cp/except.c    |   9 +-
 gcc/cp/init.c      |  11 +-
 gcc/cp/mangle.c    |   9 +-
 gcc/cp/method.c    |   4 +-
 gcc/cp/parser.c    | 178 ++++---------------
 gcc/cp/pt.c        | 429 +++++++++++++++++++++++++++------------------
 gcc/cp/rtti.c      |   8 +-
 gcc/cp/search.c    |   4 +-
 gcc/cp/semantics.c | 123 +++++++++++--
 gcc/cp/typeck.c    |  25 ++-
 18 files changed, 522 insertions(+), 927 deletions(-)

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index d1de6c3bf6d7..888f0310a7eb 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,59 @@
+2003-07-07  Mark Mitchell  <mark@codesourcery.com>
+
+	* cp-tree.h (build_scoped_method_call): Remove.
+	(lookup_qualified_name): Remove parameter.
+	(tsubst_copy_and_build): Declare.
+	(finish_qualified_object_call_expr): Remove.
+	(check_accessibility_of_qualified_id): New function.
+	(finish_qualified_id_expr): Likewise.
+	(non_reference): Likewise.
+	(build_expr_from-tree): Remove.
+	* call.c (non_reference): Remove.
+	(build_scoped_method_call): Likewise.
+	(build_method_call): Use error_operand_p.  Assert that we are not
+	processing a template.
+	(standard_conversion): Use non_reference.
+	* class.c (build_vtbl_entry_ref): Likewise.
+	(build_vtbl_ref_1): Likewise.
+	* cvt.c (build_expr_type_conversion): Use non_reference.
+	* decl.c (lookup_qualified_name): Remove flags parameter.
+	(grok_op_properties): Use non_reference.
+	* decl2.c (grok_array_decl): Likewise.
+	(build_expr_from_tree): Remove.
+	(build_offset_ref_call_from_tree): Update comment.
+	* error.c (parm_to_string): Call reinit_global_formatting_buffer.
+	* except.c (prepare_eh_types): Use non_reference.
+	(can_convert_eh): Likewise.
+	* init.c (build_dtor_call): Avoid using build_method_call.
+	* mangle.c (write_template_param): Remove misleading comment.
+	* method.c (locate_copy): Use non_reference.
+	* parser.c (cp_parser_scope_through_which_access_occurs): Remove.
+	(cp_parser_primary_expression): Do not create SCOPE_REFs is
+	non-dependent contexts.
+	(cp_parser_postfix_expression): Use finish_qualified_id_expr.
+	(cp_parser_direct_declarator): Use tsubst_copy_and_build, not
+	build_expr_from_tree.
+	(cp_parser_lookup_name): Adjust call to lookup_qualified_name.
+	Use check_accessibility_of_qualified_id.
+	* pt.c (maybe_fold_nontype_arg): Use tsubst_copy_and_build, not
+	build_expr_from_tree.
+	(tsubst_baselink): New function.
+	(tsubst_qualified_id): Likewise.
+	(tsubst_copy): Use them.  Remove support for METHOD_CALL_EXPR.
+	(tsubst_expr): Adjust call to lookup_qualified_name.
+	(tsubst_copy_and_build): Handle SCOPE_REFs specially.  Adjust
+	handling of CALL_EXPRs.
+	(value_dependent_expression_p): Use INTEGRAL_OR_ENUMERATION_TYPE_P.
+	* rtti.c (get_tinfo_decl_dynamic): Use non_reference.
+	* search.c (check_final_overrider): Likewise.
+	* semantics.c (check_accessibility_of_qualified_id): New function.
+	(finish_qualified_object_call_expr): Remove.
+	* typeck.c (target_type): Use non_reference.
+	(cxx_sizeof_or_alignof_type): Likewise.
+	(dubious_conversion_warnings): Likewise.
+	(convert_for_initialization): Likewise.
+	(non_reference): New function.
+
 2003-07-07  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
 	* decl.c (print_binding_level, print_other_binding_stack,
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 29c00de01eb8..fbf5c06a32fe 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -87,7 +87,6 @@ static struct z_candidate *add_function_candidate
 static tree implicit_conversion (tree, tree, tree, int);
 static tree standard_conversion (tree, tree, tree);
 static tree reference_binding (tree, tree, tree, int);
-static tree non_reference (tree);
 static tree build_conv (enum tree_code, tree, tree);
 static bool is_subseq (tree, tree);
 static tree maybe_handle_ref_bind (tree *);
@@ -205,106 +204,6 @@ check_dtor_name (tree basetype, tree name)
   return false;
 }
 
-/* Build a method call of the form `EXP->SCOPES::NAME (PARMS)'.
-   This is how virtual function calls are avoided.  */
-
-tree
-build_scoped_method_call (tree exp, tree basetype, tree name, tree parms)
-{
-  /* Because this syntactic form does not allow
-     a pointer to a base class to be `stolen',
-     we need not protect the derived->base conversion
-     that happens here.
-     
-     @@ But we do have to check access privileges later.  */
-  tree binfo, decl;
-  tree type = TREE_TYPE (exp);
-
-  if (type == error_mark_node
-      || basetype == error_mark_node)
-    return error_mark_node;
-
-  if (processing_template_decl)
-    {
-      name = build_min_nt (SCOPE_REF, basetype, name);
-      return build_min_nt (METHOD_CALL_EXPR, name, exp, parms, NULL_TREE);
-    }
-
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
-
-  if (TREE_CODE (basetype) == TREE_VEC)
-    {
-      binfo = basetype;
-      basetype = BINFO_TYPE (binfo);
-    }
-  else
-    binfo = NULL_TREE;
-
-  /* Check the destructor call syntax.  */
-  if (TREE_CODE (name) == BIT_NOT_EXPR)
-    {
-      /* We can get here if someone writes their destructor call like
-	 `obj.NS::~T()'; this isn't really a scoped method call, so hand
-	 it off.  */
-      if (TREE_CODE (basetype) == NAMESPACE_DECL)
-	return build_method_call (exp, name, parms, NULL_TREE, LOOKUP_NORMAL);
-
-      if (! check_dtor_name (basetype, name))
-	error ("qualified type `%T' does not match destructor name `~%T'",
-		  basetype, TREE_OPERAND (name, 0));
-
-      /* Destructors can be "called" for simple types; see 5.2.4 and 12.4 Note
-	 that explicit ~int is caught in the parser; this deals with typedefs
-	 and template parms.  */
-      if (! IS_AGGR_TYPE (basetype))
-	{
-	  if (TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (basetype))
-	    error ("type of `%E' does not match destructor type `%T' (type was `%T')",
-		      exp, basetype, type);
-
-	  return convert_to_void (exp, /*implicit=*/NULL);
-	}
-    }
-
-  if (TREE_CODE (basetype) == NAMESPACE_DECL)
-    {
-      error ("`%D' is a namespace", basetype);
-      return error_mark_node;
-    }
-  if (! is_aggr_type (basetype, 1))
-    return error_mark_node;
-
-  if (! IS_AGGR_TYPE (type))
-    {
-      error ("base object `%E' of scoped method call is of non-aggregate type `%T'",
-		exp, type);
-      return error_mark_node;
-    }
-
-  decl = build_scoped_ref (exp, basetype, &binfo);
-
-  if (binfo)
-    {
-      /* Call to a destructor.  */
-      if (TREE_CODE (name) == BIT_NOT_EXPR)
-	{
-	  if (! TYPE_HAS_DESTRUCTOR (TREE_TYPE (decl)))
-	    return convert_to_void (exp, /*implicit=*/NULL);
-	  
-	  return build_delete (TREE_TYPE (decl), decl, 
-			       sfk_complete_destructor,
-			       LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR,
-			       0);
-	}
-
-      /* Call to a method.  */
-      return build_method_call (decl, name, parms, binfo,
-				LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
-    }
-  return error_mark_node;
-}
-
 /* We want the address of a function or method.  We avoid creating a
    pointer-to-member function.  */
 
@@ -460,14 +359,12 @@ build_method_call (tree instance, tree name, tree parms,
   n_build_method_call++;
 #endif
 
-  if (instance == error_mark_node
+  if (error_operand_p (instance)
       || name == error_mark_node
-      || parms == error_mark_node
-      || (instance && TREE_TYPE (instance) == error_mark_node))
+      || parms == error_mark_node)
     return error_mark_node;
 
-  if (processing_template_decl)
-    return build_min_nt (METHOD_CALL_EXPR, name, instance, parms, NULL_TREE);
+  my_friendly_assert (!processing_template_decl, 20030707);
 
   if (TREE_CODE (TREE_TYPE (instance)) == REFERENCE_TYPE)
     instance = convert_from_reference (instance);
@@ -518,7 +415,7 @@ build_method_call (tree instance, tree name, tree parms,
   else
     fn = lookup_member (object_type, name, /*protect=*/2, /*want_type=*/false);
   
-  if (fn && TREE_CODE (fn) == TREE_LIST && !BASELINK_P (fn))
+  if (fn && TREE_CODE (fn) == TREE_LIST)
     {
       error ("request for member `%D' is ambiguous", name);
       print_candidates (fn);
@@ -669,17 +566,6 @@ build_conv (enum tree_code code, tree type, tree from)
   return t;
 }
 
-/* If T is a REFERENCE_TYPE return the type to which T refers.
-   Otherwise, return T itself.  */
-
-static tree
-non_reference (tree t)
-{
-  if (TREE_CODE (t) == REFERENCE_TYPE)
-    t = TREE_TYPE (t);
-  return t;
-}
-
 tree
 strip_top_quals (tree t)
 {
@@ -699,8 +585,7 @@ standard_conversion (tree to, tree from, tree expr)
   tree conv;
   bool fromref = false;
 
-  if (TREE_CODE (to) == REFERENCE_TYPE)
-    to = TREE_TYPE (to);
+  to = non_reference (to);
   if (TREE_CODE (from) == REFERENCE_TYPE)
     {
       fromref = true;
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 00e66078984b..5c276a4a3d03 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -401,9 +401,7 @@ build_vtable_entry_ref (tree array_ref, tree instance, tree idx)
 {
   tree i, i2, vtable, first_fn, basetype;
 
-  basetype = TREE_TYPE (instance);
-  if (TREE_CODE (basetype) == REFERENCE_TYPE)
-    basetype = TREE_TYPE (basetype);
+  basetype = non_reference (TREE_TYPE (instance));
 
   vtable = get_vtbl_decl_for_binfo (TYPE_BINFO (basetype));
   first_fn = TYPE_BINFO_VTABLE (basetype);
@@ -439,9 +437,7 @@ build_vtbl_ref_1 (tree instance, tree idx)
   int cdtorp = 0;
   tree fixed_type = fixed_type_or_null (instance, NULL, &cdtorp);
 
-  tree basetype = TREE_TYPE (instance);
-  if (TREE_CODE (basetype) == REFERENCE_TYPE)
-    basetype = TREE_TYPE (basetype);
+  tree basetype = non_reference (TREE_TYPE (instance));
 
   if (fixed_type && !cdtorp)
     {
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 85815a2c43d5..9d383cf24aef 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3493,7 +3493,6 @@ extern GTY(()) operator_name_info_t assignment_operator_name_info
 extern bool check_dtor_name (tree, tree);
 
 extern tree build_vfield_ref			(tree, tree);
-extern tree build_scoped_method_call (tree, tree, tree, tree);
 extern tree build_conditional_expr		(tree, tree, tree);
 extern tree build_addr_func (tree);
 extern tree build_call (tree, tree);
@@ -3660,7 +3659,7 @@ extern tree make_typename_type			(tree, tree, tsubst_flags_t);
 extern tree make_unbound_class_template		(tree, tree, tsubst_flags_t);
 extern tree lookup_name_nonclass		(tree);
 extern tree lookup_function_nonclass            (tree, tree);
-extern tree lookup_qualified_name               (tree, tree, bool, int);
+extern tree lookup_qualified_name               (tree, tree, bool);
 extern tree lookup_name				(tree, int);
 extern tree lookup_name_current_level		(tree);
 extern tree lookup_type_current_level		(tree);
@@ -3775,7 +3774,6 @@ extern void import_export_decl (tree);
 extern void import_export_tinfo	(tree, tree, bool);
 extern void finish_file				(void);
 extern tree build_cleanup			(tree);
-extern tree build_expr_from_tree		(tree);
 extern tree build_offset_ref_call_from_tree     (tree, tree);
 extern tree build_call_from_tree                (tree, tree, bool);
 extern void set_decl_namespace (tree, tree, bool);
@@ -3967,6 +3965,7 @@ 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);
@@ -4114,7 +4113,6 @@ 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_qualified_object_call_expr   (tree, tree, tree);
 extern tree finish_pseudo_destructor_expr       (tree, tree, tree);
 extern tree finish_unary_op_expr                (enum tree_code, tree);
 extern tree finish_compound_literal             (tree, tree);
@@ -4149,6 +4147,8 @@ extern tree begin_global_stmt_expr              (void);
 extern tree finish_global_stmt_expr             (tree);
 extern tree check_template_template_default_arg (tree);
 extern void expand_or_defer_fn			(tree);
+extern void check_accessibility_of_qualified_id (tree, tree, tree);
+extern tree finish_qualified_id_expr            (tree, tree, bool, bool);
 
 /* in tree.c */
 extern void lang_check_failed			(const char *, int,
@@ -4299,6 +4299,7 @@ extern tree check_return_expr                   (tree);
 extern tree build_ptrmemfunc_access_expr       (tree, tree);
 extern tree build_address                       (tree);
 extern tree build_nop                           (tree, tree);
+extern tree non_reference                       (tree);
 
 /* in typeck2.c */
 extern void require_complete_eh_spec_types	(tree, tree);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 081d3b8caca9..bc9b309fa25e 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -1077,9 +1077,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
       if (winner && winner == cand)
 	continue;
 
-      candidate = TREE_TYPE (TREE_TYPE (cand));
-      if (TREE_CODE (candidate) == REFERENCE_TYPE)
-	candidate = TREE_TYPE (candidate);
+      candidate = non_reference (TREE_TYPE (TREE_TYPE (cand)));
 
       switch (TREE_CODE (candidate))
 	{
@@ -1117,9 +1115,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
 
   if (winner)
     {
-      tree type = TREE_TYPE (TREE_TYPE (winner));
-      if (TREE_CODE (type) == REFERENCE_TYPE)
-	type = TREE_TYPE (type);
+      tree type = non_reference (TREE_TYPE (TREE_TYPE (winner)));
       return build_user_type_conversion (type, expr, LOOKUP_NORMAL);
     }
 
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 54c2336be117..f0aef38513f2 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5770,8 +5770,10 @@ qualify_lookup (tree val, int flags)
    declaration found.  */
 
 tree
-lookup_qualified_name (tree scope, tree name, bool is_type_p, int flags)
+lookup_qualified_name (tree scope, tree name, bool is_type_p)
 {
+  int flags = 0;
+
   if (TREE_CODE (scope) == NAMESPACE_DECL)
     {
       cxx_binding binding;
@@ -5780,12 +5782,15 @@ lookup_qualified_name (tree scope, tree name, bool is_type_p, int flags)
       flags |= LOOKUP_COMPLAIN;
       if (is_type_p)
 	flags |= LOOKUP_PREFER_TYPES;
-      if (!qualified_lookup_using_namespace (name, scope, &binding, flags))
+      if (!qualified_lookup_using_namespace (name, scope, &binding, 
+					     flags))
 	return NULL_TREE;
       return select_decl (&binding, flags);
     }
-  else
+  else if (is_aggr_type (scope, /*or_else=*/1))
     return lookup_member (scope, name, 0, is_type_p);
+  else
+    return error_mark_node;
 }
 
 /* Check to see whether or not DECL is a variable that would have been
@@ -12320,9 +12325,7 @@ grok_op_properties (tree decl, int friendp)
 	      if (p)
 		for (; TREE_CODE (TREE_VALUE (p)) != VOID_TYPE ; p = TREE_CHAIN (p))
 		  {
-		    tree arg = TREE_VALUE (p);
-		    if (TREE_CODE (arg) == REFERENCE_TYPE)
-		      arg = TREE_TYPE (arg);
+		    tree arg = non_reference (TREE_VALUE (p));
 
 		    /* This lets bad template code slip through.  */
 		    if (IS_AGGR_TYPE (arg)
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 39f6ca553691..7158f1021471 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -409,8 +409,7 @@ grok_array_decl (tree array_expr, tree index_exp)
 
   my_friendly_assert (type, 20030626);
 
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
+  type = non_reference (type);
 
   /* If they have an `operator[]', use that.  */
   if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
@@ -2938,415 +2937,6 @@ finish_file ()
   input_location = locus;
 }
 
-/* T is the parse tree for an expression.  Return the expression after
-   performing semantic analysis.  */
-
-tree
-build_expr_from_tree (tree t)
-{
-  if (t == NULL_TREE || t == error_mark_node)
-    return t;
-
-  switch (TREE_CODE (t))
-    {
-    case IDENTIFIER_NODE:
-      return do_identifier (t, NULL_TREE);
-
-    case LOOKUP_EXPR:
-      if (LOOKUP_EXPR_GLOBAL (t))
-	{
-	  tree token = TREE_OPERAND (t, 0);
-	  return do_scoped_id (token, IDENTIFIER_GLOBAL_VALUE (token));
-	}
-      else
-	{
-	  t = do_identifier (TREE_OPERAND (t, 0), NULL_TREE);
-	  if (TREE_CODE (t) == ALIAS_DECL)
-	    t = DECL_INITIAL (t);
-	  return t;
-	}
-
-    case TEMPLATE_ID_EXPR:
-      {
-	tree template;
-	tree args;
-	tree object;
-
-	template = build_expr_from_tree (TREE_OPERAND (t, 0));
-	args = build_expr_from_tree (TREE_OPERAND (t, 1));
-	
-	if (TREE_CODE (template) == COMPONENT_REF)
-	  {
-	    object = TREE_OPERAND (template, 0);
-	    template = TREE_OPERAND (template, 1);
-	  }
-	else
-	  object = NULL_TREE;
-
-	template = lookup_template_function (template, args);
-	if (object)
-	  return build (COMPONENT_REF, TREE_TYPE (template), 
-			object, template);
-	else
-	  return template;
-      }
-
-    case INDIRECT_REF:
-      return build_x_indirect_ref
-	(build_expr_from_tree (TREE_OPERAND (t, 0)), "unary *");
-
-    case CAST_EXPR:
-      return build_functional_cast
-	(TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
-
-    case REINTERPRET_CAST_EXPR:
-      return build_reinterpret_cast
-	(TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
-
-    case CONST_CAST_EXPR:
-      return build_const_cast
-	(TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
-
-    case DYNAMIC_CAST_EXPR:
-      return build_dynamic_cast
-	(TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
-
-    case STATIC_CAST_EXPR:
-      return build_static_cast
-	(TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
-
-    case PREDECREMENT_EXPR:
-    case PREINCREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-    case POSTINCREMENT_EXPR:
-    case NEGATE_EXPR:
-    case BIT_NOT_EXPR:
-    case ABS_EXPR:
-    case TRUTH_NOT_EXPR:
-    case ADDR_EXPR:
-    case CONVERT_EXPR:      /* Unary + */
-    case REALPART_EXPR:
-    case IMAGPART_EXPR:
-      if (TREE_TYPE (t))
-	return t;
-      return build_x_unary_op (TREE_CODE (t),
-			       build_expr_from_tree (TREE_OPERAND (t, 0)));
-
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-    case MULT_EXPR:
-    case TRUNC_DIV_EXPR:
-    case CEIL_DIV_EXPR:
-    case FLOOR_DIV_EXPR:
-    case ROUND_DIV_EXPR:
-    case EXACT_DIV_EXPR:
-    case BIT_AND_EXPR:
-    case BIT_ANDTC_EXPR:
-    case BIT_IOR_EXPR:
-    case BIT_XOR_EXPR:
-    case TRUNC_MOD_EXPR:
-    case FLOOR_MOD_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case RSHIFT_EXPR:
-    case LSHIFT_EXPR:
-    case RROTATE_EXPR:
-    case LROTATE_EXPR:
-    case EQ_EXPR:
-    case NE_EXPR:
-    case MAX_EXPR:
-    case MIN_EXPR:
-    case LE_EXPR:
-    case GE_EXPR:
-    case LT_EXPR:
-    case GT_EXPR:
-    case MEMBER_REF:
-      return build_x_binary_op
-	(TREE_CODE (t), 
-	 build_expr_from_tree (TREE_OPERAND (t, 0)),
-	 build_expr_from_tree (TREE_OPERAND (t, 1)));
-
-    case DOTSTAR_EXPR:
-      return build_m_component_ref
-	(build_expr_from_tree (TREE_OPERAND (t, 0)),
-	 build_expr_from_tree (TREE_OPERAND (t, 1)));
-
-    case SCOPE_REF:
-      return build_offset_ref (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1));
-
-    case ARRAY_REF:
-      if (TREE_OPERAND (t, 0) == NULL_TREE)
-	/* new-type-id */
-	return build_nt (ARRAY_REF, NULL_TREE,
-			 build_expr_from_tree (TREE_OPERAND (t, 1)));
-      return grok_array_decl (build_expr_from_tree (TREE_OPERAND (t, 0)),
-			      build_expr_from_tree (TREE_OPERAND (t, 1)));
-
-    case SIZEOF_EXPR:
-    case ALIGNOF_EXPR:
-      {
-	tree r = build_expr_from_tree (TREE_OPERAND (t, 0));
-	if (!TYPE_P (r))
-	  return TREE_CODE (t) == SIZEOF_EXPR ? expr_sizeof (r) : c_alignof_expr (r);
-	else
-	  return cxx_sizeof_or_alignof_type (r, TREE_CODE (t), true);
-      }
-
-    case MODOP_EXPR:
-      return build_x_modify_expr
-	(build_expr_from_tree (TREE_OPERAND (t, 0)),
-	 TREE_CODE (TREE_OPERAND (t, 1)),
-	 build_expr_from_tree (TREE_OPERAND (t, 2)));
-
-    case ARROW_EXPR:
-      return build_x_arrow
-	(build_expr_from_tree (TREE_OPERAND (t, 0)));
-
-    case NEW_EXPR:
-      return build_new
-	(build_expr_from_tree (TREE_OPERAND (t, 0)),
-	 build_expr_from_tree (TREE_OPERAND (t, 1)),
-	 build_expr_from_tree (TREE_OPERAND (t, 2)),
-	 NEW_EXPR_USE_GLOBAL (t));
-
-    case DELETE_EXPR:
-      return delete_sanity
-	(build_expr_from_tree (TREE_OPERAND (t, 0)),
-	 build_expr_from_tree (TREE_OPERAND (t, 1)),
-	 DELETE_EXPR_USE_VEC (t), DELETE_EXPR_USE_GLOBAL (t));
-
-    case COMPOUND_EXPR:
-      if (TREE_OPERAND (t, 1) == NULL_TREE)
-	return build_x_compound_expr
-	  (build_expr_from_tree (TREE_OPERAND (t, 0)));
-      else
-	abort ();
-
-    case METHOD_CALL_EXPR:
-      if (TREE_CODE (TREE_OPERAND (t, 0)) == SCOPE_REF)
-	{
-	  tree ref = TREE_OPERAND (t, 0);
-	  tree name = TREE_OPERAND (ref, 1);
-	  
-	  if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
-	    name = build_nt (TEMPLATE_ID_EXPR,
-	                     TREE_OPERAND (name, 0),
-	                     build_expr_from_tree (TREE_OPERAND (name, 1)));
-	    
-	  return build_scoped_method_call
-	    (build_expr_from_tree (TREE_OPERAND (t, 1)),
-	     build_expr_from_tree (TREE_OPERAND (ref, 0)),
-	     name,
-	     build_expr_from_tree (TREE_OPERAND (t, 2)));
-	}
-      else 
-	{
-	  tree fn = TREE_OPERAND (t, 0);
-
-	  /* We can get a TEMPLATE_ID_EXPR here on code like:
-
-	       x->f<2>();
-	      
-	     so we must resolve that.  However, we can also get things
-	     like a BIT_NOT_EXPR here, when referring to a destructor,
-	     and things like that are not correctly resolved by
-	     build_expr_from_tree.  So, just use build_expr_from_tree
-	     when we really need it.  */
-	  if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
-	    fn = lookup_template_function
-	      (TREE_OPERAND (fn, 0),
-	       build_expr_from_tree (TREE_OPERAND (fn, 1)));
-
-	  return build_method_call
-	    (build_expr_from_tree (TREE_OPERAND (t, 1)),
-	     fn,
-	     build_expr_from_tree (TREE_OPERAND (t, 2)),
-	     NULL_TREE, LOOKUP_NORMAL);
-	}
-
-    case CALL_EXPR:
-      if (TREE_CODE (TREE_OPERAND (t, 0)) == SCOPE_REF)
-	{
-	  tree ref = TREE_OPERAND (t, 0);
-	  tree name = TREE_OPERAND (ref, 1);
-	  tree fn, scope, args;
-	  
-	  if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
-	    name = build_nt (TEMPLATE_ID_EXPR,
-	                     TREE_OPERAND (name, 0),
-	                     build_expr_from_tree (TREE_OPERAND (name, 1)));
-
-	  scope = build_expr_from_tree (TREE_OPERAND (ref, 0));
-	  args = build_expr_from_tree (TREE_OPERAND (t, 1));
-	  fn = resolve_scoped_fn_name (scope, name);
-	  
-	  return build_call_from_tree (fn, args, 1);
-	}
-      else
-	{
-	  tree name = TREE_OPERAND (t, 0);
-          tree id;
-          tree args = build_expr_from_tree (TREE_OPERAND (t, 1));
-          if (args != NULL_TREE && TREE_CODE (name) == LOOKUP_EXPR
-              && !LOOKUP_EXPR_GLOBAL (name)
-              && TREE_CODE ((id = TREE_OPERAND (name, 0))) == IDENTIFIER_NODE
-              && (!current_class_type
-                  || !lookup_member (current_class_type, id, 0, false)))
-            {
-              /* Do Koenig lookup if there are no class members.  */
-              name = do_identifier (id, args);
-            }
-          else if (TREE_CODE (name) == TEMPLATE_ID_EXPR
-		   || ! really_overloaded_fn (name))
-	    name = build_expr_from_tree (name);
-
-	  if (TREE_CODE (name) == OFFSET_REF)
-	    return build_offset_ref_call_from_tree (name, args);
-	  if (TREE_CODE (name) == COMPONENT_REF)
-	    return finish_object_call_expr (TREE_OPERAND (name, 1),
-					    TREE_OPERAND (name, 0),
-					    args);
-	  name = convert_from_reference (name);
-	  return build_call_from_tree (name, args, 
-				       /*disallow_virtual=*/false);
-	}
-
-    case COND_EXPR:
-      return build_x_conditional_expr
-	(build_expr_from_tree (TREE_OPERAND (t, 0)),
-	 build_expr_from_tree (TREE_OPERAND (t, 1)),
-	 build_expr_from_tree (TREE_OPERAND (t, 2)));
-
-    case PSEUDO_DTOR_EXPR:
-      return (finish_pseudo_destructor_expr 
-	      (build_expr_from_tree (TREE_OPERAND (t, 0)),
-	       build_expr_from_tree (TREE_OPERAND (t, 1)),
-	       build_expr_from_tree (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 = build_expr_from_tree (purpose);
-	value = TREE_VALUE (t);
-	if (value)
-	  value = build_expr_from_tree (value);
-	chain = TREE_CHAIN (t);
-	if (chain && chain != void_type_node)
-	  chain = build_expr_from_tree (chain);
-	return tree_cons (purpose, value, chain);
-      }
-
-    case COMPONENT_REF:
-      {
-	tree object = build_expr_from_tree (TREE_OPERAND (t, 0));
-	tree member = TREE_OPERAND (t, 1);
-
-	if (!CLASS_TYPE_P (TREE_TYPE (object)))
-	  {
-	    if (TREE_CODE (member) == BIT_NOT_EXPR)
-	      return finish_pseudo_destructor_expr (object, 
-						    NULL_TREE,
-						    TREE_TYPE (object));
-	    else if (TREE_CODE (member) == SCOPE_REF
-		     && (TREE_CODE (TREE_OPERAND (member, 1)) == BIT_NOT_EXPR))
-	      return finish_pseudo_destructor_expr (object, 
-						    TREE_OPERAND (t, 0),
-						    TREE_TYPE (object));
-	  }
-	else if (TREE_CODE (member) == SCOPE_REF
-		 && TREE_CODE (TREE_OPERAND (member, 1)) == TEMPLATE_ID_EXPR)
-	  {
-	    tree tmpl;
-	    tree args;
-	
-	    /* Lookup the template functions now that we know what the
-	       scope is.  */
-	    tmpl = TREE_OPERAND (TREE_OPERAND (member, 1), 0);
-	    args = TREE_OPERAND (TREE_OPERAND (member, 1), 1);
-	    member = lookup_qualified_name (TREE_OPERAND (member, 0),
-					    tmpl, 
-					    /*is_type=*/0,
-					    /*flags=*/0);
-	    if (BASELINK_P (member))
-	      BASELINK_FUNCTIONS (member) 
-		= build_nt (TEMPLATE_ID_EXPR, BASELINK_FUNCTIONS (member),
-			    args);
-	    else
-	      {
-		error ("`%D' is not a member of `%T'",
-		       tmpl, TREE_TYPE (object));
-		return error_mark_node;
-	      }
-	  }
-
-
-	return finish_class_member_access_expr (object, member);
-      }
-
-    case THROW_EXPR:
-      return build_throw (build_expr_from_tree (TREE_OPERAND (t, 0)));
-
-    case CONSTRUCTOR:
-      {
-	tree r;
-	tree elts;
-	tree type = TREE_TYPE (t);
-	bool purpose_p;
-
-	/* digest_init will do the wrong thing if we let it.  */
-	if (type && TYPE_PTRMEMFUNC_P (type))
-	  return t;
-
-	r = NULL_TREE;
-	/* We do not want to process the purpose of aggregate
-	   initializers as they are identifier nodes which will be
-	   looked up by digest_init.  */
-	purpose_p = !(type && IS_AGGR_TYPE (type));
-	for (elts = CONSTRUCTOR_ELTS (t); elts; elts = TREE_CHAIN (elts))
-	  {
-	    tree purpose = TREE_PURPOSE (elts);
-	    tree value = TREE_VALUE (elts);
-	    
-	    if (purpose && purpose_p)
-	      purpose = build_expr_from_tree (purpose);
-	    value = build_expr_from_tree (value);
-	    r = tree_cons (purpose, value, r);
-	  }
-	
-	r = build_constructor (NULL_TREE, nreverse (r));
-	TREE_HAS_CONSTRUCTOR (r) = TREE_HAS_CONSTRUCTOR (t);
-
-	if (type)
-	  return digest_init (type, r, 0);
-	return r;
-      }
-
-    case TYPEID_EXPR:
-      if (TYPE_P (TREE_OPERAND (t, 0)))
-	return get_typeid (TREE_OPERAND (t, 0));
-      return build_typeid (build_expr_from_tree (TREE_OPERAND (t, 0)));
-
-    case PARM_DECL:
-    case VAR_DECL:
-      return convert_from_reference (t);
-
-    case VA_ARG_EXPR:
-      return build_va_arg (build_expr_from_tree (TREE_OPERAND (t, 0)),
-			   TREE_TYPE (t));
-
-    default:
-      return t;
-    }
-}
-
 /* FN is an OFFSET_REF indicating the function to call in parse-tree
    form; it has not yet been semantically analyzed.  ARGS are the
    arguments to the function.  They have already been semantically
@@ -3359,22 +2949,12 @@ build_offset_ref_call_from_tree (tree fn, tree args)
 
   my_friendly_assert (TREE_CODE (fn) == OFFSET_REF, 20020725);
 
-  /* A qualified name corresponding to a non-static member
-     function or a pointer-to-member is represented as an 
-     OFFSET_REF.  
-
-     For both of these function calls, FN will be an OFFSET_REF.
-
-	struct A { void f(); };
-	void A::f() { (A::f) (); } 
+  /* A qualified name corresponding to a bound pointer-to-member is
+     represented as an OFFSET_REF:
 
 	struct B { void g(); };
 	void (B::*p)();
 	void B::g() { (this->*p)(); }  */
-
-  /* This code is not really correct (for example, it does not
-     handle the case that `A::f' is overloaded), but it is
-     historically how we have handled this situation.  */
   if (TREE_CODE (TREE_OPERAND (fn, 1)) == FIELD_DECL)
     /* This case should now be handled elsewhere.  */
     abort ();
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 17dc1185cdbe..a9f5b15834ac 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -2230,6 +2230,8 @@ language_to_string (enum languages c)
 static const char *
 parm_to_string (int p)
 {
+  reinit_global_formatting_buffer ();
+
   if (p < 0)
     output_add_string (scratch_buffer, "'this'");
   else
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 70c446d7c596..390f12c45514 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -107,8 +107,7 @@ prepare_eh_type (tree type)
     return error_mark_node;
 
   /* peel back references, so they match.  */
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
+  type = non_reference (type);
 
   /* Peel off cv qualifiers.  */
   type = TYPE_MAIN_VARIANT (type);
@@ -872,10 +871,8 @@ nothrow_libfn_p (tree fn)
 static int
 can_convert_eh (tree to, tree from)
 {
-  if (TREE_CODE (to) == REFERENCE_TYPE)
-    to = TREE_TYPE (to);
-  if (TREE_CODE (from) == REFERENCE_TYPE)
-    from = TREE_TYPE (from);
+  to = non_reference (to);
+  from = non_reference (from);
 
   if (TREE_CODE (to) == POINTER_TYPE && TREE_CODE (from) == POINTER_TYPE)
     {
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 18a4dcf988ea..f89b4248e65f 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2915,7 +2915,7 @@ static tree
 build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
 {
   tree name;
-
+  tree fn;
   switch (dtor_kind)
     {
     case sfk_complete_destructor:
@@ -2933,8 +2933,13 @@ build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
     default:
       abort ();
     }
-  return build_method_call (exp, name, NULL_TREE, 
-			    TYPE_BINFO (TREE_TYPE (exp)), flags);
+
+  exp = convert_from_reference (exp);
+  fn = lookup_fnfields (TREE_TYPE (exp), name, /*protect=*/2);
+  return build_new_method_call (exp, fn, 
+				/*args=*/NULL_TREE,
+				/*conversion_path=*/NULL_TREE,
+				flags);
 }
 
 /* Generate a call to a destructor. TYPE is the type to cast ADDR to.
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 49a956886a71..63c58baf059e 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -2197,14 +2197,7 @@ write_pointer_to_member_type (const tree type)
    TEMPLATE_TEMPLATE_PARM, BOUND_TEMPLATE_TEMPLATE_PARM or a
    TEMPLATE_PARM_INDEX.
 
-     <template-param> ::= T </parameter/ number> _
-
-   If we are internally mangling then we distinguish level and, for
-   non-type parms, type too. The mangling appends
-   
-     </level/ number> _ </non-type type/ type> _
-
-   This is used by mangle_conv_op_name_for_type.  */
+     <template-param> ::= T </parameter/ number> _  */
 
 static void
 write_template_param (const tree parm)
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index a0d8b63c9721..e1ffaad3769a 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1000,9 +1000,7 @@ locate_copy (tree type, void *client_)
       parms = TREE_CHAIN (parms);
       if (!parms)
         continue;
-      src_type = TREE_VALUE (parms);
-      if (TREE_CODE (src_type) == REFERENCE_TYPE)
-        src_type = TREE_TYPE (src_type);
+      src_type = non_reference (TREE_VALUE (parms));
       if (!same_type_ignoring_top_level_qualifiers_p (src_type, type))
         continue;
       if (!sufficient_parms_p (TREE_CHAIN (parms)))
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 1fd2ead6ab9a..27e73cb967fa 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1717,8 +1717,6 @@ static bool cp_parser_is_string_literal
   (cp_token *);
 static bool cp_parser_is_keyword 
   (cp_token *, enum rid);
-static tree cp_parser_scope_through_which_access_occurs
-  (tree, tree, tree);
 
 /* Returns nonzero if we are parsing tentatively.  */
 
@@ -1744,62 +1742,6 @@ cp_parser_is_keyword (cp_token* token, enum rid keyword)
   return token->keyword == keyword;
 }
 
-/* Returns the scope through which DECL is being accessed, or
-   NULL_TREE if DECL is not a member.  If OBJECT_TYPE is non-NULL, we
-   have just seen `x->' or `x.' and OBJECT_TYPE is the type of `*x',
-   or `x', respectively.  If the DECL was named as `A::B' then
-   NESTED_NAME_SPECIFIER is `A'.  */
-
-static tree
-cp_parser_scope_through_which_access_occurs (tree decl, 
-					     tree object_type,
-					     tree nested_name_specifier)
-{
-  tree scope;
-  tree qualifying_type = NULL_TREE;
-  
-  /* Determine the SCOPE of DECL.  */
-  scope = context_for_name_lookup (decl);
-  /* If the SCOPE is not a type, then DECL is not a member.  */
-  if (!TYPE_P (scope))
-    return NULL_TREE;
-  /* Figure out the type through which DECL is being accessed.  */
-  if (object_type 
-      /* OBJECT_TYPE might not be a class type; consider:
-
-	   class A { typedef int I; };
-	   I *p;
-	   p->A::I::~I();
-
-         In this case, we will have "A::I" as the DECL, but "I" as the
-	 OBJECT_TYPE.  */
-      && CLASS_TYPE_P (object_type)
-      && DERIVED_FROM_P (scope, object_type))
-    /* If we are processing a `->' or `.' expression, use the type of the
-       left-hand side.  */
-    qualifying_type = object_type;
-  else if (nested_name_specifier)
-    {
-      /* If the reference is to a non-static member of the
-	 current class, treat it as if it were referenced through
-	 `this'.  */
-      if (DECL_NONSTATIC_MEMBER_P (decl)
-	  && current_class_ptr
-	  && DERIVED_FROM_P (scope, current_class_type))
-	qualifying_type = current_class_type;
-      /* Otherwise, use the type indicated by the
-	 nested-name-specifier.  */
-      else
-	qualifying_type = nested_name_specifier;
-    }
-  else
-    /* Otherwise, the name must be from the current class or one of
-       its bases.  */
-    qualifying_type = currently_open_derived_class (scope);
-
-  return qualifying_type;
-}
-
 /* Issue the indicated error MESSAGE.  */
 
 static void
@@ -2600,7 +2542,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	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.  */
@@ -2710,7 +2652,8 @@ cp_parser_primary_expression (cp_parser *parser,
 	       we will resolve the name at instantiation time.  */
 	    if (dependent_p)
 	      {
-		/* Create a SCOPE_REF for qualified names.  */
+		/* Create a SCOPE_REF for qualified names, if the
+		   scope is dependent.  */
 		if (parser->scope)
 		  {
 		    if (TYPE_P (parser->scope))
@@ -2720,9 +2663,13 @@ cp_parser_primary_expression (cp_parser *parser,
 		       might be constant when things are instantiated.  */
 		    if (parser->constant_expression_p)
 		      parser->non_constant_expression_p = true;
-		    return build_nt (SCOPE_REF, 
-				     parser->scope, 
-				     id_expression);
+		    if (TYPE_P (parser->scope)
+			&& dependent_type_p (parser->scope))
+		      return build_nt (SCOPE_REF, 
+				       parser->scope, 
+				       id_expression);
+		    else
+		      return decl;
 		  }
 		/* A TEMPLATE_ID already contains all the information
 		   we need.  */
@@ -3523,7 +3470,6 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
      form a pointer-to-member.  In that case, QUALIFYING_CLASS is the
      class used to qualify the member.  */
   tree qualifying_class = NULL_TREE;
-  bool done;
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
@@ -3752,68 +3698,28 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
       break;
     }
 
-  /* Peek at the next token.  */
-  token = cp_lexer_peek_token (parser->lexer);
-  done = (token->type != CPP_OPEN_SQUARE
-	  && token->type != CPP_OPEN_PAREN
-	  && token->type != CPP_DOT
-	  && token->type != CPP_DEREF
-	  && token->type != CPP_PLUS_PLUS
-	  && token->type != CPP_MINUS_MINUS);
-
-  /* If the postfix expression is complete, finish up.  */
-  if (address_p && qualifying_class && done)
-    {
-      if (TREE_CODE (postfix_expression) == SCOPE_REF)
-	postfix_expression = TREE_OPERAND (postfix_expression, 1);
-      postfix_expression 
-	= build_offset_ref (qualifying_class, postfix_expression);
-      return postfix_expression;
-    }
-
-  /* Otherwise, if we were avoiding committing until we knew
-     whether or not we had a pointer-to-member, we now know that
-     the expression is an ordinary reference to a qualified name.  */
+  /* If we were avoiding committing to the processing of a
+     qualified-id until we knew whether or not we had a
+     pointer-to-member, we now know.  */
   if (qualifying_class)
     {
-      if (TREE_CODE (postfix_expression) == FIELD_DECL)
-	postfix_expression 
-	  = finish_non_static_data_member (postfix_expression,
-					   qualifying_class);
-      else if (BASELINK_P (postfix_expression) 
-	       && !processing_template_decl)
-	{
-	  tree fn;
-	  tree fns;
+      bool done;
 
-	  /* See if any of the functions are non-static members.  */
-	  fns = BASELINK_FUNCTIONS (postfix_expression);
-	  if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
-	    fns = TREE_OPERAND (fns, 0);
-	  for (fn = fns; fn; fn = OVL_NEXT (fn))
-	    if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
-	      break;
-	  /* If so, the expression may be relative to the current
-	     class.  */
-	  if (fn && current_class_type 
-	      && DERIVED_FROM_P (qualifying_class, current_class_type))
-	    postfix_expression 
-	      = (build_class_member_access_expr 
-		 (maybe_dummy_object (qualifying_class, NULL),
-		  postfix_expression,
-		  BASELINK_ACCESS_BINFO (postfix_expression),
-		  /*preserve_reference=*/false));
-	  else if (done)
-	    {
-	      /* The expression is a qualified name whose address is not
-		 being taken.  */
-	      postfix_expression = build_offset_ref (qualifying_class,
-						     postfix_expression);
-	      if (TREE_CODE (postfix_expression) == OFFSET_REF)
-		postfix_expression = resolve_offset_ref (postfix_expression);
-	      return postfix_expression;
-	    }
-	}
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      done = (token->type != CPP_OPEN_SQUARE
+	      && token->type != CPP_OPEN_PAREN
+	      && token->type != CPP_DOT
+	      && token->type != CPP_DEREF
+	      && token->type != CPP_PLUS_PLUS
+	      && token->type != CPP_MINUS_MINUS);
+
+      postfix_expression = finish_qualified_id_expr (qualifying_class,
+						     postfix_expression,
+						     done,
+						     address_p);
+      if (done)
+	return postfix_expression;
     }
 
   /* Remember that there was a reference to this entity.  */
@@ -3915,7 +3821,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
 		if (!arg)
 		  {
 		    postfix_expression 
-		      = lookup_arg_dependent(identifier, functions, args);
+		      = lookup_arg_dependent (identifier, functions, args);
 		    if (!postfix_expression)
 		      {
 			/* The unqualified name could not be resolved.  */
@@ -4014,8 +3920,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
 		   may have reference type even when the standard says
 		   it does not.  Therefore, we have to manually obtain
 		   the underlying type here.  */
-		if (TREE_CODE (scope) == REFERENCE_TYPE)
-		  scope = TREE_TYPE (scope);
+		scope = non_reference (scope);
 		/* If the SCOPE is an OFFSET_TYPE, then we grab the
 		   type of the field.  We get an OFFSET_TYPE for
 		   something like:
@@ -10031,7 +9936,10 @@ cp_parser_direct_declarator (cp_parser* parser,
 
 		  saved_processing_template_decl = processing_template_decl;
 		  processing_template_decl = 0;
-		  bounds = build_expr_from_tree (bounds);
+		  bounds = tsubst_copy_and_build (bounds, 
+						  /*args=*/NULL_TREE,
+						  tf_error,
+						  /*in_decl=*/NULL_TREE);
 		  processing_template_decl = saved_processing_template_decl;
 		}
 	    }
@@ -13209,8 +13117,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
 	     may be instantiated during name lookup.  In that case,
 	     errors may be issued.  Even if we rollback the current
 	     tentative parse, those errors are valid.  */
-	  decl = lookup_qualified_name (parser->scope, name, is_type,
-					/*flags=*/0);
+	  decl = lookup_qualified_name (parser->scope, name, is_type);
 	  if (dependent_p)
 	    pop_scope (parser->scope);
 	}
@@ -13282,18 +13189,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
      During an explicit instantiation, access is not checked at all,
      as per [temp.explicit].  */
   if (DECL_P (decl))
-    {
-      tree qualifying_type;
-      
-      /* Figure out the type through which DECL is being
-	 accessed.  */
-      qualifying_type 
-	= cp_parser_scope_through_which_access_occurs (decl,
-						       object_type,
-						       parser->scope);
-      if (qualifying_type)
-	perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl);
-    }
+    check_accessibility_of_qualified_id (decl, object_type, parser->scope);
 
   return decl;
 }
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index af3b55602962..60383ef914ab 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -171,7 +171,6 @@ static bool dependent_template_id_p (tree, tree);
 static tree tsubst (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_expr	(tree, tree, tsubst_flags_t, tree);
 static tree tsubst_copy	(tree, tree, tsubst_flags_t, tree);
-static tree tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree);
 
 /* Make the current scope suitable for access checking when we are
    processing T.  T can be FUNCTION_DECL for instantiated function
@@ -5527,9 +5526,8 @@ maybe_fold_nontype_arg (tree arg)
 	 template constant parameter, like N - 1.  Now that we've
 	 tsubst'd, we might have something like 2 - 1.  This will
 	 confuse lookup_template_class, so we do constant folding
-	 here.  We have to unset processing_template_decl, to
-	 fool build_expr_from_tree() into building an actual
-	 tree.  */
+	 here.  We have to unset processing_template_decl, to fool
+	 tsubst_copy_and_build() into building an actual tree.  */
 
       /* If the TREE_TYPE of ARG is not NULL_TREE, ARG is already
 	 as simple as it's going to get, and trying to reprocess
@@ -5538,7 +5536,10 @@ maybe_fold_nontype_arg (tree arg)
 	{
 	  int saved_processing_template_decl = processing_template_decl; 
 	  processing_template_decl = 0;
-	  arg = build_expr_from_tree (arg);
+	  arg = tsubst_copy_and_build (arg,
+				       /*args=*/NULL_TREE,
+				       tf_error,
+				       /*in_decl=*/NULL_TREE);
 	  processing_template_decl = saved_processing_template_decl; 
 	}
 
@@ -7076,6 +7077,118 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     }
 }
 
+/* Like tsubst_expr for a BASELINK.  OBJECT_TYPE, if non-NULL, is the
+   type of the expression on the left-hand side of the "." or "->"
+   operator.  */
+
+static tree
+tsubst_baselink (tree baselink, tree object_type,
+		 tree args, tsubst_flags_t complain, tree in_decl)
+{
+    tree name;
+    tree qualifying_scope;
+    tree fns;
+    tree template_args = 0;
+    bool template_id_p = false;
+
+    /* A baselink indicates a function from a base class.  The
+       BASELINK_ACCESS_BINFO and BASELINK_BINFO are going to have
+       non-dependent types; otherwise, the lookup could not have
+       succeeded.  However, they may indicate bases of the template
+       class, rather than the instantiated class.  
+
+       In addition, lookups that were not ambiguous before may be
+       ambiguous now.  Therefore, we perform the lookup again. */
+    qualifying_scope = BINFO_TYPE (BASELINK_ACCESS_BINFO (baselink));
+    fns = BASELINK_FUNCTIONS (baselink);
+    if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
+      {
+	template_id_p = true;
+	template_args = TREE_OPERAND (fns, 1);
+	fns = TREE_OPERAND (fns, 0);
+	template_args = tsubst_copy (template_args, args,
+				     complain, in_decl);
+	maybe_fold_nontype_args (template_args);
+      }
+    name = DECL_NAME (get_first_fn (fns));
+    baselink = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
+    if (BASELINK_P (baselink) && template_id_p)
+      BASELINK_FUNCTIONS (baselink) 
+	= build_nt (TEMPLATE_ID_EXPR,
+		    BASELINK_FUNCTIONS (baselink),
+		    template_args);
+    if (!object_type)
+      object_type = current_class_type;
+    return adjust_result_of_qualified_name_lookup (baselink, 
+						   qualifying_scope,
+						   object_type);
+}
+
+/* Like tsubst_expr for a SCOPE_REF, given by QUALIFIED_ID.  DONE is
+   true if the qualified-id will be a postfix-expression in-and-of
+   itself; false if more of the postfix-expression follows the
+   QUALIFIED_ID.  ADDRESS_P is true if the qualified-id is the operand
+   of "&".  */
+
+static tree
+tsubst_qualified_id (tree qualified_id, tree args, 
+		     tsubst_flags_t complain, tree in_decl,
+		     bool done, bool address_p)
+{
+  tree expr;
+  tree scope;
+  tree name;
+  bool is_template;
+  tree template_args;
+
+  my_friendly_assert (TREE_CODE (qualified_id) == SCOPE_REF, 20030706);
+
+  /* Look up the qualified name.  */
+  scope = TREE_OPERAND (qualified_id, 0);
+  scope = tsubst (scope, args, complain, in_decl);
+
+  /* Figure out what name to look up.  */
+  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;
+      template_args = NULL_TREE;
+    }
+
+  expr = tsubst_copy (name, args, complain, in_decl);
+  if (!BASELINK_P (name))
+    {
+      expr = lookup_qualified_name (scope, expr, /*is_type_p=*/0);
+      if (DECL_P (expr))
+	check_accessibility_of_qualified_id (expr, 
+					     /*object_type=*/NULL_TREE,
+					     scope);
+    }
+
+  /* Remember that there was a reference to this entity.  */
+  if (DECL_P (expr))
+    mark_used (expr);
+
+  if (is_template)
+    lookup_template_function (expr, template_args);
+
+  if (TYPE_P (scope))
+    {
+      expr = (adjust_result_of_qualified_name_lookup 
+	      (expr, scope, current_class_type));
+      expr = finish_qualified_id_expr (scope, expr, done, address_p);
+    }
+
+  return expr;
+}
+
 /* Like tsubst, but deals with expressions.  This function just replaces
    template parms; to finish processing the resultant expression, use
    tsubst_expr.  */
@@ -7157,43 +7270,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       return t;
 
     case BASELINK:
-      {
-	tree name;
-	tree qualifying_scope;
-	tree fns;
-	tree template_args = 0;
-	bool template_id_p = false;
-
-	/* A baselink indicates a function from a base class.  The
-	   BASELINK_ACCESS_BINFO and BASELINK_BINFO are going to have
-	   non-dependent types; otherwise, the lookup could not have
-	   succeeded.  However, they may indicate bases of the template
-	   class, rather than the instantiated class.  
-	   
-	   In addition, lookups that were not ambiguous before may be
-	   ambiguous now.  Therefore, we perform the lookup again.  */
-	qualifying_scope = BINFO_TYPE (BASELINK_ACCESS_BINFO (t));
-	fns = BASELINK_FUNCTIONS (t);
-	if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
-	  {
-	    template_id_p = true;
-	    template_args = TREE_OPERAND (fns, 1);
-	    fns = TREE_OPERAND (fns, 0);
-	    template_args = tsubst_copy (template_args, args,
-					 complain, in_decl);
-	    maybe_fold_nontype_args (template_args);
-	  }
-	name = DECL_NAME (get_first_fn (fns));
-	t = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
-	if (BASELINK_P (t) && template_id_p)
-	  BASELINK_FUNCTIONS (t) 
-	    = build_nt (TEMPLATE_ID_EXPR,
-			BASELINK_FUNCTIONS (t),
-			template_args);
-	return adjust_result_of_qualified_name_lookup (t, 
-						       qualifying_scope,
-						       current_class_type);
-      }
+      return tsubst_baselink (t, current_class_type, args, complain, in_decl);
 
     case TEMPLATE_DECL:
       if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
@@ -7296,8 +7373,13 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	    name = build1 (BIT_NOT_EXPR, NULL_TREE, name);
 	    name = build_nt (SCOPE_REF, base, name);
 	  }
+	else if (TREE_CODE (name) == BASELINK)
+	  name = tsubst_baselink (name, 
+				  non_reference (TREE_TYPE (object)), 
+				  args, complain, 
+				  in_decl);
 	else
-	  name = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
+	  name = tsubst_copy (name, args, complain, in_decl);
 	return build_nt (COMPONENT_REF, object, name);
       }
 
@@ -7352,14 +7434,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 				    in_decl),
 		       NULL_TREE);
 
-    case METHOD_CALL_EXPR:
-      return build_nt
-	(code, 
-	 tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl),
-	 tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl),
-	 tsubst_copy (TREE_OPERAND (t, 2), args, complain, in_decl),
-	 NULL_TREE);
-
     case STMT_EXPR:
       /* This processing should really occur in tsubst_expr.  However,
 	 tsubst_expr does not recurse into expressions, since it
@@ -7547,8 +7621,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	    scope = tsubst_expr (scope, args, complain, in_decl);
 	    do_local_using_decl (lookup_qualified_name (scope,
 							name, 
-							/*is_type_p=*/0,
-							/*flags=*/0));
+							/*is_type_p=*/0));
 	  }
 	else
 	  {
@@ -7814,12 +7887,14 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 /* Like tsubst but deals with expressions and performs semantic
    analysis.  */
 
-static tree
+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;
 
@@ -7859,9 +7934,11 @@ tsubst_copy_and_build (tree t,
       {
 	tree object;
 	tree template
-	  = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
+	  = tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, 
+				   in_decl);
 	tree targs
-	  = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
+	  = tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain, 
+				   in_decl);
 	
 	if (TREE_CODE (template) == COMPONENT_REF)
 	  {
@@ -7870,7 +7947,6 @@ tsubst_copy_and_build (tree t,
 	  }
 	else
 	  object = NULL_TREE;
-	maybe_fold_nontype_args (targs);
 	template = lookup_template_function (template, targs);
 	
 	if (object)
@@ -7910,10 +7986,21 @@ tsubst_copy_and_build (tree t,
 	(tsubst (TREE_TYPE (t), args, complain, in_decl),
 	 tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
 
-    case PREDECREMENT_EXPR:
-    case PREINCREMENT_EXPR:
     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:
       if (TREE_TYPE (t))
 	return tsubst_copy (t, args, complain, in_decl);
       else
@@ -7939,8 +8026,16 @@ tsubst_copy_and_build (tree t,
 	(TREE_CODE (t),
 	 tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
 
-    case TRUTH_NOT_EXPR:
     case ADDR_EXPR:
+      op1 = TREE_OPERAND (t, 0);
+      if (TREE_CODE (op1) == SCOPE_REF)
+	op1 = tsubst_qualified_id (op1, args, complain, in_decl, 
+				   /*done=*/true, /*address_p=*/true);
+      else
+	op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
+      return build_x_unary_op (ADDR_EXPR, op1);
+
+    case TRUTH_NOT_EXPR:
     case CONVERT_EXPR:  /* Unary + */
     case REALPART_EXPR:
     case IMAGPART_EXPR:
@@ -7994,26 +8089,31 @@ tsubst_copy_and_build (tree t,
 	 tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain, in_decl));
 
     case SCOPE_REF:
-      return build_offset_ref
-	(tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl),
-	 tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl));
+      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));
-	
-	return grok_array_decl
-	  (tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
-				  in_decl),
+      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:
@@ -8034,8 +8134,16 @@ tsubst_copy_and_build (tree t,
 	 tsubst_copy_and_build (TREE_OPERAND (t, 2), args, complain, in_decl));
 
     case ARROW_EXPR:
-      return build_x_arrow
-	(tsubst_copy_and_build (TREE_OPERAND (t, 0), 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 build_x_arrow (op1);
 
     case NEW_EXPR:
       return build_new
@@ -8062,104 +8170,62 @@ tsubst_copy_and_build (tree t,
 	  abort ();
       }
 
-    case METHOD_CALL_EXPR:
+    case CALL_EXPR:
       {
-	tree method
-	  = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	
-	if (TREE_CODE (method) == SCOPE_REF)
+	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)
 	  {
-	    tree name = TREE_OPERAND (method, 1);
-	  
-	    if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
-	      name = build_nt (TEMPLATE_ID_EXPR,
-			       TREE_OPERAND (name, 0),
-			       TREE_OPERAND (name, 1));
-	    
-	    return build_scoped_method_call
-	      (tsubst_copy_and_build
-	       (TREE_OPERAND (t, 1), args, complain, in_decl),
-	       TREE_OPERAND (method, 0),
-	       name,
-	       tsubst_copy_and_build
-	       (TREE_OPERAND (t, 2), args, complain, in_decl));
+	    qualified_p = true;
+	    function = tsubst_qualified_id (function, args, complain, in_decl,
+					    /*done=*/false, 
+					    /*address_p=*/false);
 	  }
-	else 
+	else
 	  {
-	    /* We can get a TEMPLATE_ID_EXPR here on code like:
-
-	    x->f<2>();
-	      
-	    so we must resolve that.  However, we can also get things
-	    like a BIT_NOT_EXPR here, when referring to a destructor,
-	    and things like that are not correctly resolved by this
-	    function so just use it when we really need it.  */
-	    if (TREE_CODE (method) == TEMPLATE_ID_EXPR)
-	      method = lookup_template_function
-		(TREE_OPERAND (method, 0),
-		 TREE_OPERAND (method, 1));
-
-	    return build_method_call
-	      (tsubst_copy_and_build
-	       (TREE_OPERAND (t, 1), args, complain, in_decl),
-	       method,
-	       tsubst_copy_and_build
-	       (TREE_OPERAND (t, 2), args, complain, in_decl),
-	       NULL_TREE, LOOKUP_NORMAL);
+	    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);
 	  }
-      }
 
-    case CALL_EXPR:
-      {
-	tree function, copy_args;
+	/* Remember that there was a reference to this entity.  */
+	if (DECL_P (function))
+	  mark_used (function);
 
-	function = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
-	copy_args = tsubst_copy_and_build (TREE_OPERAND (t, 1), args,
+	call_args = tsubst_copy_and_build (TREE_OPERAND (t, 1), args,
 					   complain, in_decl);
 	  
 	if (BASELINK_P (function))
-	  return build_call_from_tree (function, copy_args, 1);
-	else if (TREE_CODE (function) == SCOPE_REF)
-	  {
-	    tree name = TREE_OPERAND (function, 1);
-	    if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
-	      name = build_nt (TEMPLATE_ID_EXPR,
-			       TREE_OPERAND (name, 0),
-			       build_expr_from_tree (TREE_OPERAND (name, 1)));
-	    
-	    function = resolve_scoped_fn_name (TREE_OPERAND (function, 0),
-					       name);
-	    
-	    return build_call_from_tree (function, copy_args, 1);
-	  }
+	  return build_call_from_tree (function, call_args, 1);
 	else
 	  {
-	    tree name = function;
-	    tree id;
-	    
-	    if (copy_args != NULL_TREE && TREE_CODE (name) == LOOKUP_EXPR
-		&& !LOOKUP_EXPR_GLOBAL (name)
-		&& (TREE_CODE ((id = TREE_OPERAND (name, 0)))
-		    == IDENTIFIER_NODE)
-		&& (!current_class_type
-		    || !lookup_member (current_class_type, id, 0, false)))
-	      {
-		/* Do Koenig lookup if there are no class members.  */
-		name = do_identifier (id, copy_args);
-	      }
-	    else if (TREE_CODE (name) == TEMPLATE_ID_EXPR
-		     || ! really_overloaded_fn (name))
-	      name = build_expr_from_tree (name);
-
-	    if (TREE_CODE (name) == OFFSET_REF)
-	      return build_offset_ref_call_from_tree (name, copy_args);
-	    if (TREE_CODE (name) == COMPONENT_REF)
-	      return finish_object_call_expr (TREE_OPERAND (name, 1),
-					      TREE_OPERAND (name, 0),
-					      copy_args);
-	    name = convert_from_reference (name);
-	    return build_call_from_tree (name, copy_args, 
-					 /*disallow_virtual=*/false);
+	    if (call_args != NULL_TREE && koenig_name)
+	      function = lookup_arg_dependent (koenig_name,
+					       function, 
+					       call_args);
+
+	    if (TREE_CODE (function) == OFFSET_REF)
+	      return build_offset_ref_call_from_tree (function, call_args);
+	    if (TREE_CODE (function) == COMPONENT_REF)
+	      return (build_new_method_call 
+		      (TREE_OPERAND (function, 0),
+		       TREE_OPERAND (function, 1),
+		       call_args, NULL_TREE, 
+		       qualified_p ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL));
+	    return finish_call_expr (function, call_args, 
+				     /*disallow_virtual=*/qualified_p);
 	  }
       }
 
@@ -8200,10 +8266,27 @@ tsubst_copy_and_build (tree t,
 
     case COMPONENT_REF:
       {
-	tree object =
-	  tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl);
-	tree member =
-	  tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
+	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);
+	if (BASELINK_P (member))
+	  member = tsubst_baselink (member, 
+				    non_reference (TREE_TYPE (object)),
+				    args, complain, in_decl);
+	else
+	  member = tsubst_copy (member, args, complain, in_decl);
 
 	if (!CLASS_TYPE_P (TREE_TYPE (object)))
 	  {
@@ -8229,8 +8312,7 @@ tsubst_copy_and_build (tree t,
 	    args = TREE_OPERAND (TREE_OPERAND (member, 1), 1);
 	    member = lookup_qualified_name (TREE_OPERAND (member, 0),
 					    tmpl, 
-					    /*is_type=*/0,
-					    /*flags=*/0);
+					    /*is_type=*/0);
 	    if (BASELINK_P (member))
 	      BASELINK_FUNCTIONS (member) 
 		= build_nt (TEMPLATE_ID_EXPR, BASELINK_FUNCTIONS (member),
@@ -8303,7 +8385,9 @@ tsubst_copy_and_build (tree t,
       return convert_from_reference (tsubst_copy (t, args, complain, in_decl));
 
     case VAR_DECL:
-      return convert_from_reference (tsubst_copy (t, args, complain, in_decl));
+      if (args)
+	t = tsubst_copy (t, args, complain, in_decl);
+      return convert_from_reference (t);
 
     case VA_ARG_EXPR:
 	return build_x_va_arg
@@ -11405,8 +11489,7 @@ value_dependent_expression_p (tree expression)
      with an expression that is value-dependent.  */
   if (TREE_CODE (expression) == VAR_DECL
       && DECL_INITIAL (expression)
-      && (CP_INTEGRAL_TYPE_P (TREE_TYPE (expression))
-	  || TREE_CODE (TREE_TYPE (expression)) == ENUMERAL_TYPE)
+      && INTEGRAL_OR_ENUMERATION_TYPE_P (expression)
       && value_dependent_expression_p (DECL_INITIAL (expression)))
     return true;
   /* These expressions are value-dependent if the type to which the
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index 33745e573242..b28fea6212a5 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -213,11 +213,8 @@ get_tinfo_decl_dynamic (tree exp)
   if (exp == error_mark_node)
     return error_mark_node;
 
-  type = TREE_TYPE (exp);
-
   /* peel back references, so they match.  */
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
+  type = non_reference (TREE_TYPE (exp));
 
   /* Peel off cv qualifiers.  */
   type = TYPE_MAIN_VARIANT (type);
@@ -408,8 +405,7 @@ get_typeid (tree type)
   /* If the type of the type-id is a reference type, the result of the
      typeid expression refers to a type_info object representing the
      referenced type.  */
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
+  type = non_reference (type);
 
   /* The top-level cv-qualifiers of the lvalue expression or the type-id
      that is the operand of typeid are always ignored.  */
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index cee35ff2d525..64e5707e1f0f 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1712,9 +1712,7 @@ check_final_overrider (tree overrider, tree basefn)
 	{
 	  /* can_convert will permit user defined conversion from a
 	     (reference to) class type. We must reject them.  */
-	  over_return = TREE_TYPE (over_type);
-	  if (TREE_CODE (over_return) == REFERENCE_TYPE)
-	    over_return = TREE_TYPE (over_return);
+	  over_return = non_reference (TREE_TYPE (over_type));
 	  if (CLASS_TYPE_P (over_return))
 	    fail = 2;
 	}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 9301e6595361..cc1e2ea3e9c3 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1276,6 +1276,119 @@ finish_non_static_data_member (tree decl, tree qualifying_scope)
     }
 }
 
+/* DECL was the declaration to which a qualified-id resolved.  Issue
+   an error message if it is not accessible.  If OBJECT_TYPE is
+   non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the
+   type of `*x', or `x', respectively.  If the DECL was named as
+   `A::B' then NESTED_NAME_SPECIFIER is `A'.  */
+
+void
+check_accessibility_of_qualified_id (tree decl, 
+				     tree object_type, 
+				     tree nested_name_specifier)
+{
+  tree scope;
+  tree qualifying_type = NULL_TREE;
+  
+  /* Determine the SCOPE of DECL.  */
+  scope = context_for_name_lookup (decl);
+  /* If the SCOPE is not a type, then DECL is not a member.  */
+  if (!TYPE_P (scope))
+    return;
+  /* Compute the scope through which DECL is being accessed.  */
+  if (object_type 
+      /* OBJECT_TYPE might not be a class type; consider:
+
+	   class A { typedef int I; };
+	   I *p;
+	   p->A::I::~I();
+
+         In this case, we will have "A::I" as the DECL, but "I" as the
+	 OBJECT_TYPE.  */
+      && CLASS_TYPE_P (object_type)
+      && DERIVED_FROM_P (scope, object_type))
+    /* If we are processing a `->' or `.' expression, use the type of the
+       left-hand side.  */
+    qualifying_type = object_type;
+  else if (nested_name_specifier)
+    {
+      /* If the reference is to a non-static member of the
+	 current class, treat it as if it were referenced through
+	 `this'.  */
+      if (DECL_NONSTATIC_MEMBER_P (decl)
+	  && current_class_ptr
+	  && DERIVED_FROM_P (scope, current_class_type))
+	qualifying_type = current_class_type;
+      /* Otherwise, use the type indicated by the
+	 nested-name-specifier.  */
+      else
+	qualifying_type = nested_name_specifier;
+    }
+  else
+    /* Otherwise, the name must be from the current class or one of
+       its bases.  */
+    qualifying_type = currently_open_derived_class (scope);
+
+  if (qualifying_type)
+    perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl);
+}
+
+/* EXPR is the result of a qualified-id.  The QUALIFYING_CLASS was the
+   class named to the left of the "::" operator.  DONE is true if this
+   expression is a complete postfix-expression; it is false if this
+   expression is followed by '->', '[', '(', etc.  ADDRESS_P is true
+   iff this expression is the operand of '&'.  */
+
+tree
+finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
+			  bool address_p)
+{
+  /* If EXPR occurs as the operand of '&', use special handling that
+     permits a pointer-to-member.  */
+  if (address_p && done)
+    {
+      if (TREE_CODE (expr) == SCOPE_REF)
+	expr = TREE_OPERAND (expr, 1);
+      expr = build_offset_ref (qualifying_class, expr);
+      return expr;
+    }
+
+  if (TREE_CODE (expr) == FIELD_DECL)
+    expr = finish_non_static_data_member (expr, qualifying_class);
+  else if (BASELINK_P (expr) && !processing_template_decl)
+    {
+      tree fn;
+      tree fns;
+
+      /* See if any of the functions are non-static members.  */
+      fns = BASELINK_FUNCTIONS (expr);
+      if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
+	fns = TREE_OPERAND (fns, 0);
+      for (fn = fns; fn; fn = OVL_NEXT (fn))
+	if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
+	  break;
+      /* If so, the expression may be relative to the current
+	 class.  */
+      if (fn && current_class_type 
+	  && DERIVED_FROM_P (qualifying_class, current_class_type))
+	expr = (build_class_member_access_expr 
+		(maybe_dummy_object (qualifying_class, NULL),
+		 expr,
+		 BASELINK_ACCESS_BINFO (expr),
+		 /*preserve_reference=*/false));
+      else if (done)
+	{
+	  /* The expression is a qualified name whose address is not
+	     being taken.  */
+	  expr = build_offset_ref (qualifying_class, expr);
+	  if (TREE_CODE (expr) == OFFSET_REF)
+	    expr = resolve_offset_ref (expr);
+	}
+    }
+
+  return expr;
+}
+
 /* Begin a statement-expression.  The value returned must be passed to
    finish_stmt_expr.  */
 
@@ -1548,16 +1661,6 @@ finish_object_call_expr (tree fn, tree object, tree args)
     return build_new_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
 }
 
-/* Finish a qualified member function call using OBJECT and ARGS as
-   arguments to FN.  Returns an expression for the call.  */
-
-tree 
-finish_qualified_object_call_expr (tree fn, tree object, tree args)
-{
-  return build_scoped_method_call (object, TREE_OPERAND (fn, 0),
-				   TREE_OPERAND (fn, 1), args);
-}
-
 /* Finish a pseudo-destructor expression.  If SCOPE is NULL, the
    expression was of the form `OBJECT.~DESTRUCTOR' where DESTRUCTOR is
    the TYPE for the type given.  If SCOPE is non-NULL, the expression
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 5be6aa886029..e6abb3df57f2 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -72,8 +72,7 @@ static tree lookup_destructor (tree, tree, tree);
 tree
 target_type (tree type)
 {
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
+  type = non_reference (type);
   while (TREE_CODE (type) == POINTER_TYPE
 	 || TREE_CODE (type) == ARRAY_TYPE
 	 || TREE_CODE (type) == FUNCTION_TYPE
@@ -1421,9 +1420,8 @@ cxx_sizeof_or_alignof_type (tree type, enum tree_code op, int complain)
     return build_min_nt (op, type);
   
   op_name = operator_name_info[(int) op].name;
-  
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
+
+  type = non_reference (type);
   type_code = TREE_CODE (type);
 
   if (type_code == METHOD_TYPE)
@@ -5888,8 +5886,7 @@ tree
 dubious_conversion_warnings (tree type, tree expr,
 			     const char *errtype, tree fndecl, int parmnum)
 {
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
+  type = non_reference (type);
   
   /* Issue warnings about peculiar, but valid, uses of NULL.  */
   if (ARITHMETIC_TYPE_P (type) && expr == null_node)
@@ -6102,8 +6099,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
   if (exp == error_mark_node)
     return error_mark_node;
 
-  if (TREE_CODE (rhstype) == REFERENCE_TYPE)
-    rhstype = TREE_TYPE (rhstype);
+  rhstype = non_reference (rhstype);
 
   type = complete_type (type);
 
@@ -6708,3 +6704,14 @@ strip_all_pointer_quals (tree type)
   else
     return TYPE_MAIN_VARIANT (type);
 }
+
+/* If T is a REFERENCE_TYPE return the type to which T refers.
+   Otherwise, return T itself.  */
+
+tree
+non_reference (tree t)
+{
+  if (TREE_CODE (t) == REFERENCE_TYPE)
+    t = TREE_TYPE (t);
+  return t;
+}
-- 
GitLab