OSDN Git Service

* g++.old-deja/g++.benjamin/16077.C: Adjust warnings.
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index 09ecd66..0cbff77 100644 (file)
@@ -1,22 +1,22 @@
 /* Build expressions with type checking for C++ compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
+along with GCC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
@@ -32,6 +32,8 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "rtl.h"
 #include "expr.h"
@@ -64,6 +66,7 @@ static void casts_away_constness_r PARAMS ((tree *, tree *));
 static int casts_away_constness PARAMS ((tree, tree));
 static void maybe_warn_about_returning_address_of_local PARAMS ((tree));
 static tree strip_all_pointer_quals PARAMS ((tree));
+static tree lookup_destructor (tree, tree, tree);
 
 /* Return the target type of TYPE, which means return T for:
    T*, T&, T[], T (...), and otherwise, just T.  */
@@ -155,16 +158,16 @@ complete_type (type)
   return type;
 }
 
-/* Like complete_type, but issue an error if the TYPE cannot be
-   completed.  VALUE is used for informative diagnostics.  WARN_ONLY
-   will cause a warning message to be printed, instead of an error.
+/* Like complete_type, but issue an error if the TYPE cannot be completed.
+   VALUE is used for informative diagnostics.  DIAG_TYPE indicates the type
+   of diagnostic: 0 for an error, 1 for a warning, 2 for a pedwarn.
    Returns NULL_TREE if the type cannot be made complete.  */
 
 tree
-complete_type_or_diagnostic (type, value, warn_only)
+complete_type_or_diagnostic (type, value, diag_type)
      tree type;
      tree value;
-     int warn_only;
+     int diag_type;
 {
   type = complete_type (type);
   if (type == error_mark_node)
@@ -172,7 +175,7 @@ complete_type_or_diagnostic (type, value, warn_only)
     return NULL_TREE;
   else if (!COMPLETE_TYPE_P (type))
     {
-      cxx_incomplete_type_diagnostic (value, type, warn_only);
+      cxx_incomplete_type_diagnostic (value, type, diag_type);
       return NULL_TREE;
     }
   else
@@ -203,28 +206,33 @@ qualify_type_recursive (t1, t2)
   if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
       || (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2)))
     {
-      tree tt1 = TREE_TYPE (t1);
-      tree tt2 = TREE_TYPE (t2);
+      tree tt1;
+      tree tt2;
       tree b1;
       int type_quals;
       tree tgt;
       tree attributes = (*targetm.merge_type_attributes) (t1, t2);
 
-      if (TREE_CODE (tt1) == OFFSET_TYPE)
+      if (TYPE_PTRMEM_P (t1))
        {
-         b1 = TYPE_OFFSET_BASETYPE (tt1);
-         tt1 = TREE_TYPE (tt1);
-         tt2 = TREE_TYPE (tt2);
+         b1 = TYPE_PTRMEM_CLASS_TYPE (t1);
+         tt1 = TYPE_PTRMEM_POINTED_TO_TYPE (t1);
+         tt2 = TYPE_PTRMEM_POINTED_TO_TYPE (t2);
        }
       else
-       b1 = NULL_TREE;
+       {
+         b1 = NULL_TREE;
+         tt1 = TREE_TYPE (t1);
+         tt2 = TREE_TYPE (t2);
+       }
 
       type_quals = (cp_type_quals (tt1) | cp_type_quals (tt2));
       tgt = qualify_type_recursive (tt1, tt2);
       tgt = cp_build_qualified_type (tgt, type_quals);
       if (b1)
-       tgt = build_offset_type (b1, tgt);
-      t1 = build_pointer_type (tgt);
+       t1 = build_ptrmem_type (b1, tgt);
+      else
+       t1 = build_pointer_type (tgt);
       t1 = build_type_attribute_variant (t1, attributes);
     }
   return t1;
@@ -486,7 +494,7 @@ composite_pointer_type (t1, t2, arg1, arg2, location)
     return t1;
  
   /* Deal with pointer-to-member functions in the same way as we deal
-     with pointers to functions. */
+     with pointers to functions.  */
   if (TYPE_PTRMEMFUNC_P (t1))
     t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
   if (TYPE_PTRMEMFUNC_P (t2))
@@ -795,11 +803,11 @@ comp_except_specs (t1, t2, exact)
   if (t1 == t2)
     return 1;
   
-  if (t1 == NULL_TREE)              /* T1 is ... */
+  if (t1 == NULL_TREE)              /* T1 is ...  */
     return t2 == NULL_TREE || !exact;
   if (!TREE_VALUE (t1)) /* t1 is EMPTY */
     return t2 != NULL_TREE && !TREE_VALUE (t2);
-  if (t2 == NULL_TREE)              /* T2 is ... */
+  if (t2 == NULL_TREE)              /* T2 is ...  */
     return 0;
   if (TREE_VALUE (t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
     return !exact;
@@ -938,6 +946,13 @@ comptypes (t1, t2, strict)
   if (TYPE_PTRMEMFUNC_P (t2))
     t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
 
+  /* TYPENAME_TYPEs should be resolved if the qualifying scope is the
+     current instantiation.  */
+  if (TREE_CODE (t1) == TYPENAME_TYPE)
+    t1 = resolve_typename_type_in_current_instantiation (t1);
+  if (TREE_CODE (t2) == TYPENAME_TYPE)
+    t2 = resolve_typename_type_in_current_instantiation (t2);
+
   /* Different classes of types can't be compatible.  */
   if (TREE_CODE (t1) != TREE_CODE (t2))
     return 0;
@@ -1806,7 +1821,7 @@ lookup_anon_field (t, type)
     {
       if (TREE_STATIC (field))
        continue;
-      if (TREE_CODE (field) != FIELD_DECL)
+      if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
        continue;
 
       /* If we find it directly, return the field.  */
@@ -1851,6 +1866,9 @@ build_class_member_access_expr (tree object, tree member,
   if (object == error_mark_node || member == error_mark_node)
     return error_mark_node;
 
+  if (TREE_CODE (member) == PSEUDO_DTOR_EXPR)
+    return member;
+
   my_friendly_assert (DECL_P (member) || BASELINK_P (member),
                      20020801);
 
@@ -1893,6 +1911,15 @@ build_class_member_access_expr (tree object, tree member,
       return error_mark_node;
     }
 
+  /* Transform `(a, b).x' into `(*(a, &b)).x', `(a ? b : c).x' into
+     `(*(a ?  &b : &c)).x', and so on.  A COND_EXPR is only an lvalue
+     in the frontend; only _DECLs and _REFs are lvalues in the backend.  */
+  {
+    tree temp = unary_complex_lvalue (ADDR_EXPR, object);
+    if (temp)
+      object = build_indirect_ref (temp, NULL);
+  }
+
   /* In [expr.ref], there is an explicit list of the valid choices for
      MEMBER.  We check for each of those cases here.  */
   if (TREE_CODE (member) == VAR_DECL)
@@ -1943,8 +1970,11 @@ build_class_member_access_expr (tree object, tree member,
          my_friendly_assert (object != error_mark_node,
                              20020801);
        }
-      
-      /* Issue a warning about access a member of a NULL object.  */
+
+      /* Complain about other invalid uses of offsetof, even though they will
+        give the right answer.  Note that we complain whether or not they
+        actually used the offsetof macro, since there's no way to know at this
+        point.  So we just give a warning, instead of a pedwarn.  */
       if (null_object_p && CLASSTYPE_NON_POD_P (object_type))
        {
          warning ("invalid access to non-static data member `%D' of NULL object", 
@@ -1956,7 +1986,15 @@ build_class_member_access_expr (tree object, tree member,
         OBJECT so that it refers to the class containing the
         anonymous union.  Generate a reference to the anonymous union
         itself, and recur to find MEMBER.  */
-      if (ANON_AGGR_TYPE_P (DECL_CONTEXT (member)))
+      if (ANON_AGGR_TYPE_P (DECL_CONTEXT (member))
+         /* When this code is called from build_field_call, the
+            object already has the type of the anonymous union.
+            That is because the COMPONENT_REF was already
+            constructed, and was then disassembled before calling
+            build_field_call.  After the function-call code is
+            cleaned up, this waste can be eliminated.  */
+         && (!same_type_ignoring_top_level_qualifiers_p 
+             (TREE_TYPE (object), DECL_CONTEXT (member))))
        {
          tree anonymous_union;
 
@@ -1998,6 +2036,7 @@ build_class_member_access_expr (tree object, tree member,
     {
       /* The member is a (possibly overloaded) member function.  */
       tree functions;
+      tree type;
 
       /* If the MEMBER is exactly one static member function, then we
         know the type of the expression.  Otherwise, we must wait
@@ -2005,19 +2044,12 @@ build_class_member_access_expr (tree object, tree member,
       functions = BASELINK_FUNCTIONS (member);
       if (TREE_CODE (functions) == FUNCTION_DECL
          && DECL_STATIC_FUNCTION_P (functions))
-       {
-         /* A static member function.  */
-         result = functions;
-         mark_used (result);
-         /* If OBJECT has side-effects, they are supposed to occur.  */
-         if (TREE_SIDE_EFFECTS (object))
-           result = build (COMPOUND_EXPR, TREE_TYPE (result),
-                           object, result);
-       }
+       type = TREE_TYPE (functions);
       else
-       /* Note that we do not convert OBJECT to the BASELINK_BINFO
-          base.  That will happen when the function is called.  */
-       result = build (COMPONENT_REF, unknown_type_node, object, member);
+       type = unknown_type_node;
+      /* Note that we do not convert OBJECT to the BASELINK_BINFO
+        base.  That will happen when the function is called.  */
+      result = build (COMPONENT_REF, type, object, member);
     }
   else if (TREE_CODE (member) == CONST_DECL)
     {
@@ -2044,6 +2076,34 @@ build_class_member_access_expr (tree object, tree member,
   return result;
 }
 
+/* Return the destructor denoted by OBJECT.SCOPE::~DTOR_NAME, or, if
+   SCOPE is NULL, by OBJECT.~DTOR_NAME.  */
+
+static tree
+lookup_destructor (tree object, tree scope, tree dtor_name)
+{
+  tree object_type = TREE_TYPE (object);
+  tree dtor_type = TREE_OPERAND (dtor_name, 0);
+
+  if (scope && !check_dtor_name (scope, dtor_name))
+    {
+      error ("qualified type `%T' does not match destructor name `~%T'",
+            scope, dtor_type);
+      return error_mark_node;
+    }
+  if (!same_type_p (dtor_type, TYPE_MAIN_VARIANT (object_type)))
+    {
+      error ("destructor name `%T' does not match type `%T' of expression",
+            dtor_type, object_type);
+      return error_mark_node;
+    }
+  if (!TYPE_HAS_DESTRUCTOR (object_type))
+    return build (PSEUDO_DTOR_EXPR, void_type_node, object, scope,
+                 dtor_type);
+  return lookup_member (object_type, complete_dtor_identifier,
+                       /*protect=*/1, /*want_type=*/false);
+}
+
 /* This function is called by the parser to process a class member
    access expression of the form OBJECT.NAME.  NAME is a node used by
    the parser to represent a name; it is not yet a DECL.  It may,
@@ -2130,7 +2190,7 @@ finish_class_member_access_expr (tree object, tree name)
          if (TREE_CODE (scope) == NAMESPACE_DECL)
            {
              error ("`%D::%D' is not a member of `%T'", 
-                    scope, member, object_type);
+                    scope, name, object_type);
              return error_mark_node;
            }
 
@@ -2139,34 +2199,35 @@ finish_class_member_access_expr (tree object, tree name)
          if (!access_path || access_path == error_mark_node)
            return error_mark_node;
 
-         /* Look up the member.  */
-         member = lookup_member (access_path, name, /*protect=*/1, 
-                                 /*want_type=*/0);
-         if (member == error_mark_node)
-           return error_mark_node;
-       }
-      else if (TREE_CODE (name) == BIT_NOT_EXPR)
-       {
-         /* A destructor.  */
-         if (TYPE_IDENTIFIER (object_type) != TREE_OPERAND (name, 0))
-           {
-             error ("destructor specifier `%T::~%T' must have matching names",
-                    object_type, TREE_OPERAND (name, 0));
-             return error_mark_node;
-           }
-         if (! TYPE_HAS_DESTRUCTOR (object_type))
+         if (TREE_CODE (name) == BIT_NOT_EXPR)
+           member = lookup_destructor (object, scope, name);
+         else
            {
-             error ("type `%T' has no destructor", object_type);
-             return error_mark_node;
+             /* Look up the member.  */
+             member = lookup_member (access_path, name, /*protect=*/1, 
+                                     /*want_type=*/false);
+             if (member == NULL_TREE)
+               {
+                 error ("'%D' has no member named '%E'", object_type, name);
+                 return error_mark_node;
+               }
+             if (member == error_mark_node)
+               return error_mark_node;
            }
-         member = CLASSTYPE_DESTRUCTORS (object_type);
        }
+      else if (TREE_CODE (name) == BIT_NOT_EXPR)
+       member = lookup_destructor (object, /*scope=*/NULL_TREE, name);
       else if (TREE_CODE (name) == IDENTIFIER_NODE)
        {
          /* An unqualified name.  */
          member = lookup_member (object_type, name, /*protect=*/1, 
-                                 /*want_type=*/0);
-         if (member == error_mark_node)
+                                 /*want_type=*/false);
+         if (member == NULL_TREE)
+           {
+             error ("'%D' has no member named '%E'", object_type, name);
+             return error_mark_node;
+           }
+         else if (member == error_mark_node)
            return error_mark_node;
        }
       else
@@ -2196,6 +2257,9 @@ finish_class_member_access_expr (tree object, tree name)
        }
     }
 
+  if (TREE_DEPRECATED (member))
+    warn_deprecated_use (member);
+
   return build_class_member_access_expr (object, member, access_path,
                                         /*preserve_reference=*/false);
 }
@@ -2221,7 +2285,7 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
   ptrmem_type = TREE_TYPE (ptrmem);
   my_friendly_assert (TYPE_PTRMEMFUNC_P (ptrmem_type), 20020804);
   member = lookup_member (ptrmem_type, member_name, /*protect=*/0,
-                         /*want_type=*/0);
+                         /*want_type=*/false);
   member_type = cp_build_qualified_type (TREE_TYPE (member),
                                         cp_type_quals (ptrmem_type));
   return fold (build (COMPONENT_REF, member_type, ptrmem, member));
@@ -2244,8 +2308,8 @@ build_x_indirect_ref (ptr, errorstring)
   if (processing_template_decl)
     return build_min_nt (INDIRECT_REF, ptr);
 
-  rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE,
-                        NULL_TREE);
+  rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE,
+                      NULL_TREE);
   if (rval)
     return rval;
   return build_indirect_ref (ptr, errorstring);
@@ -2288,8 +2352,7 @@ build_indirect_ref (ptr, errorstring)
           return error_mark_node;
         }
       else if (TREE_CODE (pointer) == ADDR_EXPR
-         && !flag_volatile
-         && same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))
+              && same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))
        /* The POINTER was something like `&x'.  We simplify `*&x' to
           `x'.  */
        return TREE_OPERAND (pointer, 0);
@@ -2303,8 +2366,7 @@ build_indirect_ref (ptr, errorstring)
          TREE_READONLY (ref) = CP_TYPE_CONST_P (t);
          TREE_THIS_VOLATILE (ref) = CP_TYPE_VOLATILE_P (t);
          TREE_SIDE_EFFECTS (ref)
-           = (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (pointer)
-              || flag_volatile);
+           = (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (pointer));
          return ref;
        }
     }
@@ -2486,7 +2548,7 @@ build_array_ref (array, idx)
    With the final ISO C++ rules, such an optimization is
    incorrect: A pointer to a derived member can be static_cast
    to pointer-to-base-member, as long as the dynamic object
-   later has the right member. */
+   later has the right member.  */
 
 tree
 get_member_function_from_ptrfunc (instance_ptrptr, function)
@@ -2502,13 +2564,14 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
       tree fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
 
       tree instance_ptr = *instance_ptrptr;
+      tree instance_save_expr = 0;
       if (instance_ptr == error_mark_node)
        {
          if (TREE_CODE (function) == PTRMEM_CST)
            {
              /* Extracting the function address from a pmf is only
                 allowed with -Wno-pmf-conversions. It only works for
-                pmf constants. */
+                pmf constants.  */
              e1 = build_addr_func (PTRMEM_CST_MEMBER (function));
              e1 = convert (fntype, e1);
              return e1;
@@ -2521,7 +2584,7 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
        }
 
       if (TREE_SIDE_EFFECTS (instance_ptr))
-       instance_ptr = save_expr (instance_ptr);
+       instance_ptr = instance_save_expr = save_expr (instance_ptr);
 
       if (TREE_SIDE_EFFECTS (function))
        function = save_expr (function);
@@ -2547,7 +2610,7 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
        }
 
       /* Convert down to the right base before using the instance.  First
-         use the type... */
+         use the type...  */
       basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
       basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)),
                              basetype, ba_check, NULL);
@@ -2582,9 +2645,9 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
       
       /* Make sure this doesn't get evaluated first inside one of the
         branches of the COND_EXPR.  */
-      if (TREE_CODE (instance_ptr) == SAVE_EXPR)
+      if (instance_save_expr)
        e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
-                   instance_ptr, e1);
+                   instance_save_expr, e1);
 
       function = e1;
     }
@@ -2592,9 +2655,8 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
 }
 
 tree
-build_function_call_real (function, params, require_complete, flags)
+build_function_call (function, params)
      tree function, params;
-     int require_complete, flags;
 {
   register tree fntype, fndecl;
   register tree value_type;
@@ -2668,20 +2730,10 @@ build_function_call_real (function, params, require_complete, flags)
   /* Convert the parameters to the types declared in the
      function prototype, or apply default promotions.  */
 
-  if (flags & LOOKUP_COMPLAIN)
-    coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
-                                       params, fndecl, LOOKUP_NORMAL);
-  else
-    coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
-                                       params, fndecl, 0);
-
+  coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
+                                     params, fndecl, LOOKUP_NORMAL);
   if (coerced_params == error_mark_node)
-    {
-      if (flags & LOOKUP_SPECULATIVELY)
-       return NULL_TREE;
-      else
-       return error_mark_node;
-    }
+    return error_mark_node;
 
   /* Check for errors in format strings.  */
 
@@ -2707,23 +2759,13 @@ build_function_call_real (function, params, require_complete, flags)
   result = fold (build_call (function, coerced_params));
   value_type = TREE_TYPE (result);
 
-  if (require_complete)
-    {
-      if (TREE_CODE (value_type) == VOID_TYPE)
-       return result;
-      result = require_complete_type (result);
-    }
+  if (TREE_CODE (value_type) == VOID_TYPE)
+    return result;
+  result = require_complete_type (result);
   if (IS_AGGR_TYPE (value_type))
     result = build_cplus_new (value_type, result);
   return convert_from_reference (result);
 }
-
-tree
-build_function_call (function, params)
-     tree function, params;
-{
-  return build_function_call_real (function, params, 1, LOOKUP_NORMAL);
-}
 \f
 /* Convert the actual parameter expressions in the list VALUES
    to the types in the list TYPELIST.
@@ -2864,7 +2906,8 @@ convert_arguments (typelist, values, fndecl, flags)
   if (typetail != 0 && typetail != void_list_node)
     {
       /* See if there are default arguments that can be used */
-      if (TREE_PURPOSE (typetail))
+      if (TREE_PURPOSE (typetail) 
+         && TREE_CODE (TREE_PURPOSE (typetail)) != DEFAULT_ARG)
        {
          for (; typetail != void_list_node; ++i)
            {
@@ -2914,6 +2957,183 @@ build_x_binary_op (code, arg1, arg2)
   return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
 }
 
+#if 0
+
+tree
+build_template_expr (enum tree_code code, tree op0, tree op1, tree op2)
+{
+  tree type;
+
+  /* If any of the operands is erroneous the result is erroneous too.  */
+  if (error_operand_p (op0)
+      || (op1 && error_operand_p (op1))
+      || (op2 && error_operand_p (op2)))
+    return error_mark_node;
+      
+  if (dependent_type_p (TREE_TYPE (op0))
+      || (op1 && dependent_type_p (TREE_TYPE (op1)))
+      || (op2 && dependent_type_p (TREE_TYPE (op2))))
+    /* If at least one operand has a dependent type, we cannot
+       determine the type of the expression until instantiation time.  */
+    type = NULL_TREE;
+  else
+    {
+      struct z_candidate *cand;
+      tree op0_type;
+      tree op1_type;
+      tree op2_type;
+
+      /* None of the operands is dependent, so we can compute the type
+        of the expression at this point.  We must compute the type so
+        that in things like:
+
+          template <int I>
+          void f() { S<sizeof(I + 3)> s; ... }
+
+        we can tell that the type of "s" is non-dependent.
+
+        If we're processing a template argument, we do not want to
+        actually change the operands in any way.  Adding conversions,
+        performing constant folding, etc., would all change mangled
+        names.  For example, in:
+        
+          template <int I>
+          void f(S<sizeof(3 + 4 + I)>);
+        
+        we need to determine that "3 + 4 + I" has type "int", without
+        actually turning the expression into "7 + I".  */
+      cand = find_overloaded_op (code, op0, op1, op2);
+      if (cand) 
+       /* If an overloaded operator was found, the expression will
+          have the type returned by the function.  */
+       type = non_reference (TREE_TYPE (cand->fn));
+      else
+       {
+         /* There is no overloaded operator so we can just use the
+            default rules for determining the type of the operand.  */
+         op0_type = TREE_TYPE (op0);
+         op1_type = op1 ? TREE_TYPE (op1) : NULL_TREE;
+         op2_type = op2 ? TREE_TYPE (op2) : NULL_TREE;
+         type = NULL_TREE;
+
+         switch (code)
+           {
+           case MODIFY_EXPR:
+             /* [expr.ass]
+
+                The result of the assignment operation is the value
+                stored in the left operand.  */
+             type = op0_type;
+             break;
+           case COMPONENT_REF:
+             /* Implement this case.  */
+             break;
+           case POSTINCREMENT_EXPR:
+           case POSTDECREMENT_EXPR:
+             /* [expr.post.incr]
+
+                The type of the result is the cv-unqualified version
+                of the type of the operand.  */
+             type = TYPE_MAIN_VARIANT (op0_type);
+             break;
+           case PREINCREMENT_EXPR:
+           case PREDECREMENT_EXPR:
+             /* [expr.pre.incr]
+
+                The value is the new value of the operand.  */
+             type = op0_type;
+             break;
+           case INDIRECT_REF:
+             /* [expr.unary.op]
+
+                If the type of the expression is "pointer to T", the
+                type of the result is "T".  */
+             type = TREE_TYPE (op0_type);
+             break;
+           case ADDR_EXPR:
+             /* [expr.unary.op]
+
+                If the type of the expression is "T", the type of the
+                result is "pointer to T".  */
+             /* FIXME: Handle the pointer-to-member case.  */
+             break;
+           case MEMBER_REF:
+             /* FIXME: Implement this case.  */
+             break;
+           case LSHIFT_EXPR:
+           case RSHIFT_EXPR:
+             /* [expr.shift]
+
+                The type of the result is that of the promoted left
+                operand.  */
+             break;
+           case PLUS_EXPR:
+           case MINUS_EXPR:
+             /* FIXME: Be careful of special pointer-arithmetic
+                cases.  */
+             /* Fall through. */
+           case MAX_EXPR:
+           case MIN_EXPR:
+             /* These are GNU extensions; the result type is computed
+                as it would be for other arithmetic operators.  */
+             /* Fall through. */
+           case BIT_AND_EXPR:
+           case BIT_XOR_EXPR:
+           case BIT_IOR_EXPR:
+           case MULT_EXPR:
+           case TRUNC_DIV_EXPR:
+           case TRUNC_MOD_EXPR:
+             /* [expr.bit.and], [expr.xor], [expr.or], [expr.mul]
+
+                The usual arithmetic conversions are performed on the
+                operands and determine the type of the result.  */
+             /* FIXME: Check that this is possible.  */
+             type = type_after_usual_arithmetic_conversions (t1, t2);
+             break;
+           case GT_EXPR:
+           case LT_EXPR:
+           case GE_EXPR:
+           case LE_EXPR:
+           case EQ_EXPR:
+           case NE_EXPR:
+             /* [expr.rel]
+
+                The type of the result is bool.  */
+             type = boolean_type_node;
+             break;
+           case TRUTH_ANDIF_EXPR:
+           case TRUTH_ORIF_EXPR:
+             /* [expr.log.and], [expr.log.org]
+                
+                The result is a bool.  */
+             type = boolean_type_node;
+             break;
+           case COND_EXPR:
+             /* FIXME: Handle special rules for conditioanl
+                expressions.  */
+             break;
+           case COMPOUND_EXPR:
+             type = op1_type;
+             break;
+           default:
+             abort ();
+           }
+         /* If the type of the expression could not be determined,
+            something is wrong.  */
+         if (!type)
+           abort ();
+         /* If the type is erroneous, the expression is erroneous
+            too.  */
+         if (type == error_mark_node)
+           return error_mark_node;
+       }
+    }
+  
+  return build_min (code, type, op0, op1, op2, NULL_TREE);
+}
+
+#endif
+
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
    This function differs from `build' in several ways:
@@ -3848,7 +4068,45 @@ condition_conversion (expr)
   t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
   return t;
 }
-                              
+               
+/* Return an ADDR_EXPR giving the address of T.  This function
+   attempts no optimizations or simplifications; it is a low-level
+   primitive.  */
+
+tree
+build_address (tree t)
+{
+  tree addr;
+
+  if (error_operand_p (t) || !cxx_mark_addressable (t))
+    return error_mark_node;
+
+  addr = build1 (ADDR_EXPR, 
+                build_pointer_type (TREE_TYPE (t)),
+                t);
+  if (staticp (t))
+    TREE_CONSTANT (addr) = 1;
+
+  return addr;
+}
+
+/* Return a NOP_EXPR converting EXPR to TYPE.  */
+
+tree
+build_nop (tree type, tree expr)
+{
+  tree nop;
+
+  if (type == error_mark_node || error_operand_p (expr))
+    return expr;
+    
+  nop = build1 (NOP_EXPR, type, expr);
+  if (TREE_CONSTANT (expr))
+    TREE_CONSTANT (nop) = 1;
+  
+  return nop;
+}
+
 /* C++: Must handle pointers to members.
 
    Perhaps type instantiation should be extended to handle conversion
@@ -3880,7 +4138,7 @@ build_unary_op (code, xarg, noconvert)
         is enough to prevent anybody from looking inside for
         associativity, but won't generate any code.  */
       if (!(arg = build_expr_type_conversion
-           (WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, 1)))
+           (WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, true)))
        errstring = "wrong type argument to unary plus";
       else
        {
@@ -3892,7 +4150,7 @@ build_unary_op (code, xarg, noconvert)
       break;
 
     case NEGATE_EXPR:
-      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
        errstring = "wrong type argument to unary minus";
       else if (!noconvert)
        arg = default_conversion (arg);
@@ -3906,14 +4164,14 @@ build_unary_op (code, xarg, noconvert)
            arg = default_conversion (arg);
        }
       else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM,
-                                                  arg, 1)))
+                                                  arg, true)))
        errstring = "wrong type argument to bit-complement";
       else if (!noconvert)
        arg = default_conversion (arg);
       break;
 
     case ABS_EXPR:
-      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
        errstring = "wrong type argument to abs";
       else if (!noconvert)
        arg = default_conversion (arg);
@@ -3921,7 +4179,7 @@ build_unary_op (code, xarg, noconvert)
 
     case CONJ_EXPR:
       /* Conjugating a real value is a no-op, but allow it anyway.  */
-      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
        errstring = "wrong type argument to conjugation";
       else if (!noconvert)
        arg = default_conversion (arg);
@@ -3981,7 +4239,7 @@ build_unary_op (code, xarg, noconvert)
       /* Report invalid types.  */
 
       if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_POINTER,
-                                             arg, 1)))
+                                             arg, true)))
        {
          if (code == PREINCREMENT_EXPR)
            errstring ="no pre-increment operator for type";
@@ -4190,7 +4448,7 @@ build_unary_op (code, xarg, noconvert)
              if (current_class_type
                  && TREE_OPERAND (arg, 0) == current_class_ref)
                /* An expression like &memfn.  */
-               pedwarn ("ISO C++ forbids taking the address of an unqualified non-static member function to form a pointer to member function.  Say `&%T::%D'", base, name);
+               pedwarn ("ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.  Say `&%T::%D'", base, name);
              else
                pedwarn ("ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say `&%T::%D'", base, name);
            }
@@ -4232,32 +4490,46 @@ build_unary_op (code, xarg, noconvert)
         is an error.  */
       else if (TREE_CODE (argtype) != FUNCTION_TYPE
               && TREE_CODE (argtype) != METHOD_TYPE
-              && !lvalue_or_else (arg, "unary `&'"))
+              && !non_cast_lvalue_or_else (arg, "unary `&'"))
        return error_mark_node;
 
       if (argtype != error_mark_node)
        argtype = build_pointer_type (argtype);
 
-      if (!cxx_mark_addressable (arg))
-       return error_mark_node;
-
       {
        tree addr;
 
        if (TREE_CODE (arg) == COMPONENT_REF
+           && TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
+         arg = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
+
+       if (TREE_CODE (arg) == COMPONENT_REF
            && DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
          {
            error ("attempt to take address of bit-field structure member `%D'",
                   TREE_OPERAND (arg, 1));
            return error_mark_node;
          }
+       else if (TREE_CODE (arg) == COMPONENT_REF
+                && TREE_CODE (TREE_OPERAND (arg, 0)) == INDIRECT_REF
+                && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg, 0), 0))
+                    == INTEGER_CST))
+         {
+           /* offsetof idiom, fold it.  */
+           tree field = TREE_OPERAND (arg, 1);
+           tree rval = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
+           tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (rval)),
+                                     decl_type_context (field),
+                                     ba_check, NULL);
+           
+           rval = build_base_path (PLUS_EXPR, rval, binfo, 1);
+           rval = build1 (NOP_EXPR, argtype, rval);
+           TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0));
+           addr = fold (build (PLUS_EXPR, argtype, rval,
+                               cp_convert (argtype, byte_position (field))));
+         }
        else
-         addr = build1 (ADDR_EXPR, argtype, arg);
-
-       /* Address of a static or external variable or
-          function counts as a constant */
-       if (staticp (arg))
-         TREE_CONSTANT (addr) = 1;
+         addr = build_address (arg);
 
        if (TREE_CODE (argtype) == POINTER_TYPE
            && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
@@ -4390,9 +4662,7 @@ unary_complex_lvalue (code, arg)
              return error_mark_node;
            }
 
-         type = build_offset_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
-         type = build_pointer_type (type);
-
+         type = build_ptrmem_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
          t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
          return t;
        }
@@ -4523,15 +4793,15 @@ build_x_compound_expr (list)
   if (rest == NULL_TREE)
     return build_compound_expr (list);
 
-  result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL,
-                          TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
+  result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL,
+                        TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
   if (result)
     return build_x_compound_expr (tree_cons (NULL_TREE, result,
                                                  TREE_CHAIN (rest)));
 
   if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
     {
-      /* FIXME: This test should be in the implicit cast to void of the LHS. */
+      /* FIXME: This test should be in the implicit cast to void of the LHS.  */
       /* the left-hand operand of a comma expression is like an expression
          statement: we should warn if it doesn't have any side-effects,
          unless it was explicitly cast to (void).  */
@@ -4642,12 +4912,12 @@ build_static_cast (type, expr)
       ? can_convert_arg (type, intype, expr)
       : can_convert_arg (strip_all_pointer_quals (type),
                          strip_all_pointer_quals (intype), expr))
-    /* This is a standard conversion. */
+    /* This is a standard conversion.  */
     ok = 1;
   else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype))
     {
       /* They're pointers to objects. They must be aggregates that
-         are related non-virtually. */
+         are related non-virtually.  */
       base_kind kind;
       
       if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
@@ -4660,7 +4930,7 @@ build_static_cast (type, expr)
     {
       /* They're pointers to members. The pointed to objects must be
         the same (ignoring CV qualifiers), and the containing classes
-        must be related non-virtually. */
+        must be related non-virtually.  */
       base_kind kind;
       
       if (same_type_p
@@ -5156,8 +5426,8 @@ build_modify_expr (lhs, modifycode, rhs)
            /* Do the default thing */;
          else
            {
-             result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
-                                      lhs, rhs, make_node (NOP_EXPR));
+             result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
+                                    lhs, rhs, make_node (NOP_EXPR));
              if (result == NULL_TREE)
                return error_mark_node;
              return result;
@@ -5248,7 +5518,7 @@ build_modify_expr (lhs, modifycode, rhs)
          || TREE_CODE (TREE_TYPE (lhs)) == METHOD_TYPE
          /* If it's an aggregate and any field is const, then it is
             effectively const.  */
-         || (IS_AGGR_TYPE_CODE (TREE_CODE (lhstype))
+         || (CLASS_TYPE_P (lhstype)
              && C_TYPE_FIELDS_READONLY (lhstype))))
     readonly_error (lhs, "assignment", 0);
 
@@ -5301,7 +5571,7 @@ build_modify_expr (lhs, modifycode, rhs)
 
       from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
                   ? 1 + (modifycode != INIT_EXPR): 0;
-      return build_vec_init (lhs, newrhs, from_array);
+      return build_vec_init (lhs, NULL_TREE, newrhs, from_array);
     }
 
   if (modifycode == INIT_EXPR)
@@ -5409,8 +5679,8 @@ build_x_modify_expr (lhs, modifycode, rhs)
 
   if (modifycode != NOP_EXPR)
     {
-      tree rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
-                                 make_node (modifycode));
+      tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
+                               make_node (modifycode));
       if (rval)
        return rval;
     }
@@ -5458,10 +5728,9 @@ get_delta_difference (from, to, force)
       
       if (virt_binfo)
         {
-          /* This is a reinterpret cast, we choose to do nothing. */
-          warning ("pointer to member cast via virtual base `%T' of `%T'",
-                     BINFO_TYPE (virt_binfo),
-                     BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
+          /* This is a reinterpret cast, we choose to do nothing.  */
+          warning ("pointer to member cast via virtual base `%T'",
+                  BINFO_TYPE (virt_binfo));
           return delta;
         }
       delta = BINFO_OFFSET (binfo);
@@ -5476,15 +5745,13 @@ get_delta_difference (from, to, force)
   virt_binfo = binfo_from_vbase (binfo);
   if (virt_binfo)
     {
-      /* This is a reinterpret cast, we choose to do nothing. */
+      /* This is a reinterpret cast, we choose to do nothing.  */
       if (force)
-        warning ("pointer to member cast via virtual base `%T' of `%T'",
-                    BINFO_TYPE (virt_binfo),
-                    BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
+        warning ("pointer to member cast via virtual base `%T'",
+                BINFO_TYPE (virt_binfo));
       else
-       error ("pointer to member conversion via virtual base `%T' of `%T'",
-                 BINFO_TYPE (virt_binfo),
-                  BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
+       error ("pointer to member conversion via virtual base `%T'",
+              BINFO_TYPE (virt_binfo));
       return delta;
     }
   delta = BINFO_OFFSET (binfo);
@@ -5528,7 +5795,7 @@ build_ptrmemfunc1 (type, delta, pfn)
    as a value in expressions.  TYPE is the POINTER to METHOD_TYPE we
    want to be.
 
-   If FORCE is non-zero, then force this conversion, even if
+   If FORCE is nonzero, then force this conversion, even if
    we would rather not do it.  Usually set when using an explicit
    cast.
 
@@ -5540,11 +5807,17 @@ build_ptrmemfunc (type, pfn, force)
      int force;
 {
   tree fn;
-  tree pfn_type = TREE_TYPE (pfn);
-  tree to_type = build_ptrmemfunc_type (type);
+  tree pfn_type;
+  tree to_type;
+
+  if (error_operand_p (pfn))
+    return error_mark_node;
+
+  pfn_type = TREE_TYPE (pfn);
+  to_type = build_ptrmemfunc_type (type);
 
   /* Handle multiple conversions of pointer to member functions.  */
-  if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
+  if (TYPE_PTRMEMFUNC_P (pfn_type))
     {
       tree delta = NULL_TREE;
       tree npfn = NULL_TREE;
@@ -5643,7 +5916,7 @@ expand_ptrmemfunc_cst (cst, delta, pfn)
       /* If we're dealing with a virtual function, we have to adjust 'this'
          again, to point to the base which provides the vtable entry for
          fn; the call will do the opposite adjustment.  */
-      tree orig_class = DECL_VIRTUAL_CONTEXT (fn);
+      tree orig_class = DECL_CONTEXT (fn);
       tree binfo = binfo_or_else (orig_class, fn_class);
       *delta = fold (build (PLUS_EXPR, TREE_TYPE (*delta),
                            *delta, BINFO_OFFSET (binfo)));
@@ -5803,8 +6076,16 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
   /* Simplify the RHS if possible.  */
   if (TREE_CODE (rhs) == CONST_DECL)
     rhs = DECL_INITIAL (rhs);
-  else if (coder != ARRAY_TYPE)
-    rhs = decl_constant_value (rhs);
+  
+  /* We do not use decl_constant_value here because of this case:
+
+       const char* const s = "s";
+     The conversion rules for a string literal are more lax than for a
+     variable; in particular, a string literal can be converted to a
+     "char *" but the variable "s" cannot be converted in the same
+     way.  If the conversion is allowed, the optimization should be
+     performed while creating the converted expression.  */
 
   /* [expr.ass]
 
@@ -5843,7 +6124,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
 }
 
 /* Convert RHS to be of type TYPE.
-   If EXP is non-zero, it is the target of the initialization.
+   If EXP is nonzero, it is the target of the initialization.
    ERRTYPE is a string to use in error messages.
 
    Two major differences between the behavior of
@@ -5917,7 +6198,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
 
       if (fndecl)
        savew = warningcount, savee = errorcount;
-      rhs = initialize_reference (type, rhs);
+      rhs = initialize_reference (type, rhs, /*decl=*/NULL_TREE);
       if (fndecl)
        {
          if (warningcount > savew)
@@ -5993,9 +6274,9 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       else
        {
          tree type = TREE_TYPE (o[i]);
-         if (CP_TYPE_CONST_P (type)
-             || (IS_AGGR_TYPE_CODE (TREE_CODE (type))
-                 && C_TYPE_FIELDS_READONLY (type)))
+         if (type != error_mark_node
+             && (CP_TYPE_CONST_P (type)
+                 || (CLASS_TYPE_P (type) && C_TYPE_FIELDS_READONLY (type))))
            readonly_error (o[i], "modification by `asm'", 1);
        }
     }
@@ -6097,7 +6378,7 @@ check_return_expr (retval)
     {
       if (in_function_try_handler)
        /* If a return statement appears in a handler of the
-          function-try-block of a constructor, the program is ill-formed. */
+          function-try-block of a constructor, the program is ill-formed.  */
        error ("cannot return from a handler of a function-try-block of a constructor");
       else if (retval)
        /* You can't return a value from a constructor.  */
@@ -6105,6 +6386,12 @@ check_return_expr (retval)
       return NULL_TREE;
     }
 
+  if (processing_template_decl)
+    {
+      current_function_returns_value = 1;
+      return retval;
+    }
+  
   /* When no explicit return-value is given in a function with a named
      return value, the named return value is used.  */
   result = DECL_RESULT (current_function_decl);
@@ -6218,7 +6505,7 @@ check_return_expr (retval)
 
       /* First convert the value to the function's return type, then
         to the type of return value's location to handle the
-         case that functype is smaller than the valtype. */
+         case that functype is smaller than the valtype.  */
       retval = convert_for_initialization
        (NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
         "return", NULL_TREE, 0);
@@ -6245,9 +6532,9 @@ check_return_expr (retval)
 }
 
 \f
-/* Returns non-zero if the pointer-type FROM can be converted to the
+/* Returns nonzero if the pointer-type FROM can be converted to the
    pointer-type TO via a qualification conversion.  If CONSTP is -1,
-   then we return non-zero if the pointers are similar, and the
+   then we return nonzero if the pointers are similar, and the
    cv-qualification signature of FROM is a proper subset of that of TO.
 
    If CONSTP is positive, then all outer pointers have been
@@ -6408,10 +6695,12 @@ cp_type_quals (type)
      tree type;
 {
   type = strip_array_types (type);
+  if (type == error_mark_node)
+    return TYPE_UNQUALIFIED;
   return TYPE_QUALS (type);
 }
 
-/* Returns non-zero if the TYPE contains a mutable member */
+/* Returns nonzero if the TYPE contains a mutable member */
 
 int
 cp_has_mutable_p (type)
@@ -6484,7 +6773,7 @@ casts_away_constness_r (t1, t2)
   *t2 = cp_build_qualified_type (*t2, quals2);
 }
 
-/* Returns non-zero if casting from TYPE1 to TYPE2 casts away
+/* Returns nonzero if casting from TYPE1 to TYPE2 casts away
    constness.  */
 
 static int