OSDN Git Service

59th Cygnus<->FSF merge
authormrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 23 Mar 1995 00:44:31 +0000 (00:44 +0000)
committermrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 23 Mar 1995 00:44:31 +0000 (00:44 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@9225 138bc75d-0d04-0410-961f-82ee72b054a4

17 files changed:
gcc/cp/ChangeLog
gcc/cp/Makefile.in
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/error.c
gcc/cp/expr.c
gcc/cp/init.c
gcc/cp/lex.c
gcc/cp/method.c
gcc/cp/parse.y
gcc/cp/pt.c
gcc/cp/tree.c
gcc/cp/typeck.c

index aa13e96..331e139 100644 (file)
@@ -1,3 +1,188 @@
+Wed Mar 22 15:10:34 1995  Mike Stump  <mrs@cygnus.com>
+
+       * decl2.c (finish_prevtable_vardecl, finish_vtable_vardecl): Revert
+       Brendan's last change and fix latent problem that causes TD entries
+       to not come out when the things that need them has yet to be
+       expanded.
+
+Wed Mar 22 15:12:00 1995  Jason Merrill  <jason@phydeaux.cygnus.com>
+
+       * typeck.c (build_binary_op_nodefault, comparison ops): Update type0
+       and type1, since we might have changed op0 or op1.
+
+Wed Mar 22 13:33:45 1995  Jason Merrill  <jason@python.cygnus.com>
+
+       * typeck.c (common_type): Don't mess up templates.
+
+Wed Mar 22 04:56:00 1995  Jason Merrill  <jason@phydeaux.cygnus.com>
+
+       * typeck.c (common_type): Handle ptms properly.  Also handle 
+       T* -> void*.
+       (build_binary_op_nodefault): New variable build_type controls what
+       type is given to the expression when it is created.  Set this to
+       boolean_type_node for comparison ops instead of using result_type.
+       (comp_target_types): Allow T * -> void *.
+
+       * cvt.c (cp_convert_to_pointer): Do access control when converting
+       ptms, too.
+
+Tue Mar 21 17:25:06 1995  Brendan Kehoe  (brendan@lisa.cygnus.com)
+
+       * parse.y (extern_lang_string): Catch use of linkage specs that
+       aren't all naming the same language.
+
+       * class.c (finish_struct): Delete accidental duplicate code.
+
+Tue Mar 21 14:00:57 1995  Jason Merrill  <jason@phydeaux.cygnus.com>
+
+       * typeck.c (build_binary_op_nodefault): Disable pedwarns about
+       comparing functions and incomplete types.
+
+       * decl.c (finish_function): Only unset current_function_decl if
+       !nested.
+       (duplicate_decls): Last change went too far; we only want to stop
+       checking for value/reference ambiguity.
+
+Tue Mar 21 01:26:39 1995  Mike Stump  <mrs@cygnus.com>
+
+       * gc.c (build_generic_desc): Zap the DECL_SIZE so that we can lay it
+       out fresh, as the new type may be larger.
+
+Mon Mar 20 19:01:10 1995  Jason Merrill  <jason@phydeaux.cygnus.com>
+
+       * expr.c (extract_init): Try to expand the RTL for the
+       initialization and figure out what it will look like so we can avoid
+       run-time initialization.  Disabled for now.
+       (extract_scalar_init): Helper for scalar initialization.
+       (extract_aggr_init): Helper for aggregate initialization.
+
+       * decl.c (duplicate_decls): Don't complain about ambiguous
+       declarations.
+       (obscure_complex_init): Now returns a tree.  Call extract_init if
+       we're optimizing and this is a toplevel decl.
+       (finish_decl): Update accordingly.
+
+       * lex.c (check_newline): If we're just changing files (not pushing
+       or popping), update input_file_stack->name.
+
+Mon Mar 20 17:55:04 1995  Mike Stump  <mrs@cygnus.com>
+
+       * pt.c (type_unification): Only TEMPLATE_DECLs are handled right now
+       in the transitive unification code.
+
+Mon Mar 20 16:07:50 1995  Brendan Kehoe  (brendan@lisa.cygnus.com)
+
+       * decl.c (shadow_tag): Don't allow inline, virtual, or explicit on
+       non-functions.
+       (grokdeclarator): Don't allow friends to be defined in local classes.
+
+Sat Mar 18 04:03:33 1995  Jason Merrill  <jason@phydeaux.cygnus.com>
+
+       * decl2.c (finish_prevtable_vardecl): Use DECL_DECLARED_STATIC
+       rather than DECL_SAVED_INSNS to decide whether or not this method
+       was declared inline.
+
+       * method.c (synthesize_method): Turn off DECL_INLINE if
+       function_cannot_inline_p thinks we're too large.
+
+       * typeck.c (build_indirect_ref): Use build_expr_type_conversion.
+
+Fri Mar 17 17:47:36 1995  Jason Merrill  <jason@phydeaux.cygnus.com>
+
+       * class.c (instantiate_type): Handle pmfs.
+
+       * typeck.c (convert_for_assignment): Check types when assigning one
+       pmf to another.
+
+       * decl.c (define_label): Fix logic for printing out the name of the
+       label in an error message.
+
+       * error.c (dump_expr): Support ARRAY_REF.
+
+Fri Mar 17 17:43:02 1995  Brendan Kehoe  (brendan@lisa.cygnus.com)
+
+       * decl2.c (finish_vtable_vardecl): Call build_t_desc here.
+       (finish_prevtable_vardecl): Instead of here.
+
+Fri Mar 17 14:40:45 1995  Jason Merrill  <jason@phydeaux.cygnus.com>
+
+       * decl.c (expand_static_init): Also use expand_aggr_init if the
+       initializer is a TREE_LIST.     
+       (grokdeclarator): Only pedwarn about extra qualification if -pedantic.
+
+       * pt.c (unify): Fix unification of return type.
+
+       * expr.c (fixup_result_decl): Use store_expr, rather than
+       emit_move_insn, to move the return value into the place where
+       callers will expect it.
+
+Thu Mar 16 22:05:25 1995  Jason Merrill  <jason@phydeaux.cygnus.com>
+
+       * init.c (build_offset_ref): Call assmble_external on functions.
+       * typeck.c (build_component_ref): Ditto.
+
+Thu Mar 16 20:28:16 1995  Brendan Kehoe  (brendan@lisa.cygnus.com)
+
+       * decl.c (struct saved_scope): Add members base_init_list and
+       member_init_list.
+       (push_to_top_level): Save current_base_init_list and
+       current_member_init_list to them.
+       (pop_from_top_level): Put it back.
+
+Thu Mar 16 19:21:14 1995  Jason Merrill  <jason@phydeaux.cygnus.com>
+
+       * pt.c (instantiate_template): Call assemble_external.  
+
+Thu Mar 16 18:07:54 1995  Brendan Kehoe  (brendan@phydeaux.cygnus.com)
+
+       * class.c: Include rtl.h, to get NULL_RTX.
+       (finish_struct): Also zero out DECL_SAVED_INSNS, to avoid problems
+       on hosts with different sizes for each part of the union.
+       * tree.c: Also include rtl.h.
+       (layout_basetypes): Same change for DECL_SAVED_INSNS.
+
+Thu Mar 16 13:57:36 1995  Jason Merrill  <jason@phydeaux.cygnus.com>
+
+       * pt.c (unify): Fix array domain unification for 64-bit targets.
+
+       * decl2.c (finish_file): Push bizarre type decl before walking the
+       vtables the first time.
+       (walk_vtables): OK, don't set prev to vars if the vardecl_fn messed
+       with TREE_CHAIN (prev).
+
+       * init.c (emit_base_init): Use convert_pointer_to_real instead of
+       convert_pointer_to when converting to a direct base.
+
+Wed Mar 15 20:26:29 1995  Mike Stump  <mrs@cygnus.com>
+
+       * pt.c (type_unification): Handle transitive unification better.
+
+Wed Mar 15 13:56:16 1995  Jason Merrill  <jason@phydeaux.cygnus.com>
+
+       * decl2.c (walk_vtables): Always set prev to vars.
+       (mark_vtable_entries): Call assemble_external on the vtable entries.
+
+       * class.c (finish_struct): Set the vtable's size to NULL_TREE before
+        calling layout_decl, so that it gets updated properly.
+
+       Finally re-enable dynamic synthesis.  This time it works.
+       * method.c (synthesize_method): Pass decl_function_context (fndecl)
+       to {push,pop}_cp_function_context.
+       * decl.c (push_cp_function_context): Now takes a tree argument.
+       (pop_cp_function_context): Ditto.
+       * call.c (build_method_call): Enable synthesis.
+       * lex.c (cons_up_default_function): Ditto.
+
+Tue Mar 14 19:14:19 1995  Doug Evans  <dje@chestnut.cygnus.com>
+
+       * parse.y (setattrs): Chain onto prefix_attributes rather than
+       setting it.
+
+Wed Mar 15 13:00:00 1995  Brendan Kehoe  (brendan@lisa.cygnus.com)
+
+       * decl.c (pushdecl): Check if the type of the VAR_DECL is an
+       error_mark_node before trying to read TYPE_LANG_SPECIFIC. 
+
 Mon Mar 13 21:00:28 1995  Brendan Kehoe  (brendan@lisa.cygnus.com)
 
        * decl.c (grokdeclarator, case ARRAY_REF): Wrap the exp with fold,
index dd267f3..6007f00 100644 (file)
@@ -167,6 +167,7 @@ OBJDEPS = ../stamp-objlist ../c-common.o ../c-pragma.o
 
 compiler: ../cc1plus
 ../cc1plus: $(P) $(CXX_OBJS) $(OBJDEPS) $(LIBDEPS)
+       rm -f $@
        $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o ../cc1plus \
              $(CXX_OBJS) $(OBJS) $(LIBS)
 
index 3079d14..9ba6d18 100644 (file)
@@ -2379,7 +2379,7 @@ build_method_call (instance, name, parms, basetype_path, flags)
   /* Declare external function if necessary. */
   assemble_external (function);
 
-#if 0
+#if 1
   /* Is it a synthesized method that needs to be synthesized?  */
   if (DECL_ARTIFICIAL (function) && ! flag_no_inline
       && DECL_SAVED_INSNS (function) == 0
index f296dc9..d6e2315 100644 (file)
@@ -26,6 +26,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <stdio.h>
 #include "cp-tree.h"
 #include "flags.h"
+#include "rtl.h"
 
 #include "obstack.h"
 #define obstack_chunk_alloc xmalloc
@@ -2963,6 +2964,11 @@ finish_struct (t, list_of_fieldlists, warn_anon)
 
              DECL_CLASS_CONTEXT (x) = t;
 
+             /* Do both of these, even though they're in the same union;
+                if the insn `r' member and the size `i' member are
+                different sizes, as on the alpha, the larger of the two
+                will end up with garbage in it.  */
+             DECL_SAVED_INSNS (x) = NULL_RTX;
              DECL_FIELD_SIZE (x) = 0;
 
              /* The name of the field is the original field name
@@ -3027,6 +3033,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
            fields = x;
          last_x = x;
 
+         DECL_SAVED_INSNS (x) = NULL_RTX;
          DECL_FIELD_SIZE (x) = 0;
 
          /* When this goes into scope, it will be a non-local reference.  */
@@ -3505,6 +3512,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
       DECL_FIELD_CONTEXT (vfield) = t;
       DECL_CLASS_CONTEXT (vfield) = t;
       DECL_FCONTEXT (vfield) = t;
+      DECL_SAVED_INSNS (vfield) = NULL_RTX;
       DECL_FIELD_SIZE (vfield) = 0;
       DECL_ALIGN (vfield) = TYPE_ALIGN (ptr_type_node);
       if (CLASSTYPE_RTTI (t))
@@ -3576,47 +3584,6 @@ finish_struct (t, list_of_fieldlists, warn_anon)
   TYPE_ALIGN (t) = round_up_size;
 
   /* Pass layout information about base classes to layout_type, if any.  */
-
-  {
-    tree field;
-    for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
-      {
-       if (TREE_STATIC (field))
-         continue;
-       if (TREE_CODE (field) != FIELD_DECL)
-         continue;
-
-       /* If this field is an anonymous union,
-          give each union-member the same position as the union has.
-
-          ??? This is a real kludge because it makes the structure
-          of the types look strange.  This feature is only used by
-          C++, which should have build_component_ref build two
-          COMPONENT_REF operations, one for the union and one for
-          the inner field.  We set the offset of this field to zero
-          so that either the old or the correct method will work.
-          Setting DECL_FIELD_CONTEXT is wrong unless the inner fields are
-          moved into the type of this field, but nothing seems to break
-          by doing this.  */
-
-       if (DECL_NAME (field) == NULL_TREE
-           && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
-         {
-           tree uelt = TYPE_FIELDS (TREE_TYPE (field));
-           for (; uelt; uelt = TREE_CHAIN (uelt))
-             {
-               if (TREE_CODE (uelt) != FIELD_DECL)
-                 continue;
-
-               DECL_FIELD_CONTEXT (uelt) = DECL_FIELD_CONTEXT (field);
-               DECL_FIELD_BITPOS (uelt) = DECL_FIELD_BITPOS (field);
-             }
-
-           DECL_FIELD_BITPOS (field) = integer_zero_node;
-         }
-      }
-  }
-
   if (n_baseclasses)
     {
       tree pseudo_basetype = TREE_TYPE (base_layout_decl);
@@ -3911,6 +3878,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
       if (TREE_TYPE (TYPE_BINFO_VTABLE (t)) != atype)
        {
          TREE_TYPE (TYPE_BINFO_VTABLE (t)) = atype;
+         DECL_SIZE (TYPE_BINFO_VTABLE (t)) = 0;
          layout_decl (TYPE_BINFO_VTABLE (t), 0);
          /* At one time the vtable info was grabbed 2 words at a time.  This
             fails on sparc unless you have 8-byte alignment.  (tiemann) */
@@ -4726,6 +4694,9 @@ instantiate_type (lhstype, rhs, complain)
           functions or member functions.  May have to undo what
           `default_conversion' might do to lhstype.  */
 
+       if (TYPE_PTRMEMFUNC_P (lhstype))
+         lhstype = TYPE_PTRMEMFUNC_FN_TYPE (lhstype);
+
        if (TREE_CODE (lhstype) == POINTER_TYPE)
          if (TREE_CODE (TREE_TYPE (lhstype)) == FUNCTION_TYPE
              || TREE_CODE (TREE_TYPE (lhstype)) == METHOD_TYPE)
@@ -4884,8 +4855,7 @@ instantiate_type (lhstype, rhs, complain)
 #endif
          }
        if (complain)
-         error ("no compatible member functions named `%s'",
-                IDENTIFIER_POINTER (name));
+         cp_error ("no compatible member functions named `%D'", name);
        return error_mark_node;
       }
 
index 528c23a..98ea89f 100644 (file)
@@ -1,5 +1,5 @@
 /* Definitions for C++ parsing and type checking.
-   Copyright (C) 1987, 1993, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1993, 1994, 1995 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
index e87b168..7e880b4 100644 (file)
@@ -155,6 +155,18 @@ cp_convert_to_pointer (type, expr)
          && TREE_CODE (TREE_TYPE (intype)) == METHOD_TYPE)
        return convert_fn_ptr (type, expr);
 
+      if (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE
+         && TREE_CODE (TREE_TYPE (intype)) == OFFSET_TYPE)
+       {
+         tree b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type));
+         tree b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype));
+         tree binfo = get_binfo (b1, b2, 1);
+         if (binfo == NULL_TREE)
+           binfo = get_binfo (b2, b1, 1);
+         if (binfo == error_mark_node)
+           return error_mark_node;
+       }
+
       return build1 (NOP_EXPR, type, expr);
     }
 
index 1ef0ebd..c9865e3 100644 (file)
@@ -1443,6 +1443,7 @@ struct saved_scope {
   tree old_bindings;
   struct saved_scope *prev;
   tree class_name, class_type, class_decl, function_decl;
+  tree base_init_list, member_init_list;
   struct binding_level *class_bindings;
   tree previous_class_type;
   tree *lang_base, *lang_stack, lang_name;
@@ -1519,6 +1520,8 @@ push_to_top_level ()
   s->class_type = current_class_type;
   s->class_decl = current_class_decl;
   s->function_decl = current_function_decl;
+  s->base_init_list = current_base_init_list;
+  s->member_init_list = current_member_init_list;
   s->class_bindings = class_binding_level;
   s->previous_class_type = previous_class_type;
   s->lang_stack = current_lang_stack;
@@ -1571,6 +1574,8 @@ pop_from_top_level ()
     C_C_D = CLASSTYPE_INST_VAR (current_class_type);
   else
     C_C_D = NULL_TREE;
+  current_base_init_list = s->base_init_list;
+  current_member_init_list = s->member_init_list;
   current_function_decl = s->function_decl;
   class_binding_level = s->class_bindings;
   previous_class_type = s->previous_class_type;
@@ -2230,7 +2235,7 @@ duplicate_decls (newdecl, olddecl)
              cp_error_at ("previous declaration `%#D' here", olddecl);
            }
          else if (compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
-                             TYPE_ARG_TYPES (TREE_TYPE (olddecl)), 2))
+                             TYPE_ARG_TYPES (TREE_TYPE (olddecl)), 3))
            {
              cp_error ("new declaration `%#D'", newdecl);
              cp_error_at ("ambiguates old declaration `%#D'", olddecl);
@@ -3061,6 +3066,7 @@ pushdecl (x)
       /* Keep count of variables in this level with incomplete type.  */
       /* RTTI TD entries are created while defining the type_info.  */
       if (TREE_CODE (x) == VAR_DECL
+         && TREE_TYPE (x) != error_mark_node
          && TYPE_LANG_SPECIFIC (TREE_TYPE (x))
          && TYPE_BEING_DEFINED (TREE_TYPE (x)))
        {
@@ -3606,6 +3612,7 @@ define_label (filename, line, name)
   else
     {
       tree uses, prev;
+      int identified = 0;
 
       /* Mark label as having been defined.  */
       DECL_INITIAL (decl) = error_mark_node;
@@ -3636,10 +3643,11 @@ define_label (filename, line, name)
                             && DECL_INITIAL (new_decls) != error_mark_node)
                            || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls))))
                      {
-                       if (IDENTIFIER_ERROR_LOCUS (decl) == NULL_TREE)
-                         cp_error ("invalid jump to label `%D'", decl);
-                       SET_IDENTIFIER_ERROR_LOCUS (decl, current_function_decl);
-                       cp_error ("crosses initialization of `%D'", new_decls);
+                       if (! identified)
+                         cp_error ("jump to label `%D'", decl);
+                       identified = 1;
+                       cp_error_at ("  crosses initialization of `%#D'",
+                                    new_decls);
                      }
                    new_decls = TREE_CHAIN (new_decls);
                  }
@@ -5259,7 +5267,10 @@ shadow_tag (declspecs)
       else if (value == ridpointers[(int) RID_STATIC]
               || value == ridpointers[(int) RID_EXTERN]
               || value == ridpointers[(int) RID_AUTO]
-              || value == ridpointers[(int) RID_REGISTER])
+              || value == ridpointers[(int) RID_REGISTER]
+              || value == ridpointers[(int) RID_INLINE]
+              || value == ridpointers[(int) RID_VIRTUAL]
+              || value == ridpointers[(int) RID_EXPLICIT])
        ob_modifier = value;
     }
 
@@ -5290,9 +5301,19 @@ shadow_tag (declspecs)
     {
       /* Anonymous unions are objects, that's why we only check for
         inappropriate specifiers in this branch.  */
+
       if (ob_modifier)
-       cp_error ("`%D' can only be specified for objects and functions",
-                 ob_modifier);
+       {
+         if (ob_modifier == ridpointers[(int) RID_INLINE]
+             || ob_modifier == ridpointers[(int) RID_VIRTUAL])
+           cp_error ("`%D' can only be specified for functions", ob_modifier);
+         else if (ob_modifier == ridpointers[(int) RID_EXPLICIT])
+           cp_error ("`%D' can only be specified for constructors",
+                     ob_modifier);
+         else
+           cp_error ("`%D' can only be specified for objects and functions",
+                     ob_modifier);
+       }
 
       if (found_tag == 0)
        pedwarn ("abstract declarator used as declaration");
@@ -5837,16 +5858,24 @@ grok_reference_init (decl, type, init, cleanupp)
    it in with a dummy CONSTRUCTOR to force the variable into .data;
    otherwise we can use error_mark_node.  */
 
-static void
-obscure_complex_init (decl)
-     tree decl;
+static tree
+obscure_complex_init (decl, init)
+     tree decl, init;
 {
+  if (! flag_no_inline && TREE_STATIC (decl))
+    {
+      if (extract_init (decl, init))
+       return NULL_TREE;
+    }
+
   if (current_binding_level == global_binding_level
       && ! DECL_COMMON (decl))
     DECL_INITIAL (decl) = build (CONSTRUCTOR, TREE_TYPE (decl), NULL_TREE,
                                 NULL_TREE);
   else
     DECL_INITIAL (decl) = error_mark_node;
+
+  return init;
 }
 
 /* Finish processing of a declaration;
@@ -6078,22 +6107,18 @@ finish_decl (decl, init, asmspec_tree, need_pop, flags)
                }
            }
 #endif
-
-         /* We must hide the initializer so that expand_decl
-            won't try to do something it does not understand.  */
-         obscure_complex_init (decl);
        }
       else
        {
        dont_use_constructor:
          if (TREE_CODE (init) != TREE_VEC)
            init = store_init_value (decl, init);
-
-         /* Don't let anyone try to initialize this variable
-            until we are ready to do so.  */
-         if (init)
-           obscure_complex_init (decl);
        }
+
+      if (init)
+       /* We must hide the initializer so that expand_decl
+          won't try to do something it does not understand.  */
+       init = obscure_complex_init (decl, init);
     }
   else if (DECL_EXTERNAL (decl))
     ;
@@ -6120,7 +6145,7 @@ finish_decl (decl, init, asmspec_tree, need_pop, flags)
 
       if (TYPE_SIZE (type) != NULL_TREE
          && TYPE_NEEDS_CONSTRUCTING (type))
-       obscure_complex_init (decl);
+       init = obscure_complex_init (decl, NULL_TREE);
     }
   else if (TREE_CODE (decl) == VAR_DECL
           && TREE_CODE (type) != REFERENCE_TYPE
@@ -6589,7 +6614,8 @@ expand_static_init (decl, init)
                                          integer_zero_node, 1), 0);
       old_cleanups = cleanups_this_call;
       expand_assignment (temp, integer_one_node, 0, 0);
-      if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
+      if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
+         || TREE_CODE (init) == TREE_LIST)
        {
          expand_aggr_init (decl, init, 0, 0);
          do_pending_stack_adjust ();
@@ -8372,11 +8398,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                    RIDBIT_RESET (RID_FRIEND, specbits);
                    friendp = 0;
                  }
+               if (decl_context == NORMAL)
+                 error ("friend declaration not in class definition");
+               if (current_function_decl && funcdef_flag)
+                 cp_error ("can't define friend function `%s' in a local class definition",
+                           name);
              }
 
-           if (decl_context == NORMAL && friendp)
-             error ("friend declaration not in class definition");
-
            /* Traditionally, declaring return type float means double.  */
 
            if (flag_traditional
@@ -8598,8 +8626,17 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises)
                   basetype :: member .  */
 
                if (ctype == current_class_type)
-                 cp_pedwarn ("extra qualification `%T::' on member `%s' ignored",
-                             ctype, name);
+                 {
+                   /* class A {
+                        void A::f ();
+                      };
+
+                      Is this ill-formed?  */
+
+                   if (pedantic)
+                     cp_pedwarn ("extra qualification `%T::' on member `%s' ignored",
+                                 ctype, name);
+                 }
                else if (TREE_CODE (type) == FUNCTION_TYPE)
                  {
                    if (current_class_type == NULL_TREE
@@ -11307,7 +11344,7 @@ finish_function (lineno, call_poplevel, nested)
       int ok_to_optimize_dtor = 0;
 
       if (current_function_assigns_this)
-       cond = build (NE_EXPR, integer_type_node,
+       cond = build (NE_EXPR, boolean_type_node,
                      current_class_decl, integer_zero_node);
       else
        {
@@ -11756,8 +11793,14 @@ finish_function (lineno, call_poplevel, nested)
   if (DECL_STATIC_DESTRUCTOR (fndecl))
     static_dtors = perm_tree_cons (NULL_TREE, fndecl, static_dtors);
 
-  /* Let the error reporting routines know that we're outside a function.  */
-  current_function_decl = NULL_TREE;
+  if (! nested)
+    {
+      /* Let the error reporting routines know that we're outside a
+         function.  For a nested function, this value is used in
+         pop_cp_function_context and then reset via pop_function_context.  */
+      current_function_decl = NULL_TREE;
+    }
+
   named_label_uses = NULL_TREE;
 }
 \f
@@ -12190,13 +12233,13 @@ struct cp_function *cp_function_chain;
    used during compilation of a C++ function.  */
 
 void
-push_cp_function_context (toplev)
-     int toplev;
+push_cp_function_context (context)
+     tree context;
 {
   struct cp_function *p
     = (struct cp_function *) xmalloc (sizeof (struct cp_function));
 
-  push_function_context_to (toplev);
+  push_function_context_to (context);
 
   p->next = cp_function_chain;
   cp_function_chain = p;
@@ -12221,8 +12264,8 @@ push_cp_function_context (toplev)
 /* Restore the variables used during compilation of a C++ function.  */
 
 void
-pop_cp_function_context (toplev)
-     int toplev;
+pop_cp_function_context (context)
+     tree context;
 {
   struct cp_function *p = cp_function_chain;
   tree link;
@@ -12244,7 +12287,7 @@ pop_cp_function_context (toplev)
     }
 #endif
 
-  pop_function_context_from (toplev);
+  pop_function_context_from (context);
 
   cp_function_chain = p->next;
 
index 6cc0420..633fc8b 100644 (file)
@@ -1932,7 +1932,8 @@ build_push_scope (cname, name)
   return rval;
 }
 
-void cplus_decl_attributes (decl, attributes, prefix_attributes)
+void
+cplus_decl_attributes (decl, attributes, prefix_attributes)
      tree decl, attributes, prefix_attributes;
 {
   if (decl && decl != void_type_node)
@@ -2463,7 +2464,14 @@ mark_vtable_entries (decl)
          extern tree abort_fndecl;
          if (flag_vtable_thunks)
            fnaddr = TREE_VALUE (entries);
-         TREE_OPERAND (fnaddr, 0) = abort_fndecl;
+         TREE_OPERAND (fnaddr, 0) = fn = abort_fndecl;
+       }
+      if (TREE_PUBLIC (fn) && ! TREE_ASM_WRITTEN (fn))
+       {
+         int save_extern = DECL_EXTERNAL (fn);
+         DECL_EXTERNAL (fn) = 1;
+         assemble_external (fn);
+         DECL_EXTERNAL (fn) = save_extern;
        }
     }
 }
@@ -2561,7 +2569,8 @@ finish_prevtable_vardecl (prev, vars)
       for (method = CLASSTYPE_METHODS (ctype); method != NULL_TREE;
           method = DECL_NEXT_METHOD (method))
        {
-         if (DECL_VINDEX (method) != NULL_TREE && !DECL_SAVED_INSNS (method)
+         if (DECL_VINDEX (method) != NULL_TREE
+             && !DECL_DECLARED_STATIC (method)
              && !DECL_ABSTRACT_VIRTUAL_P (method))
            {
              SET_CLASSTYPE_INTERFACE_KNOWN (ctype);
@@ -2574,10 +2583,17 @@ finish_prevtable_vardecl (prev, vars)
 
   import_export_vtable (vars, ctype, 1);
 
+  /* We cannot use TREE_USED here, as it may be set by the expanding of a
+     ctor that is used to build a global object.  The long term plan is to
+     make the TD entries statically initialized and move this to
+     finish_vtable_vardecl time.  */
   if (flag_rtti && write_virtuals >= 0
-      && ! DECL_EXTERNAL (vars) && (TREE_PUBLIC (vars) || TREE_USED (vars)))
+      && ! DECL_EXTERNAL (vars) && (TREE_PUBLIC (vars) || 1 || TREE_USED (vars)))
     {
-      /* Kick out the type descriptor before writing out the vtable.  */
+      /* Kick out the type descriptor before we dump out global
+        initializers, as they are initialized at run time and
+        we have to find them when we scan for things that need initialized
+        at the top level.  */
       build_t_desc (ctype, 1);
     }
 }
@@ -2589,6 +2605,15 @@ finish_vtable_vardecl (prev, vars)
   if (write_virtuals >= 0
       && ! DECL_EXTERNAL (vars) && (TREE_PUBLIC (vars) || TREE_USED (vars)))
     {
+#if 0
+      /* The long term plan it to make the TD entries statically initialized,
+        have the entries built and emitted here.  When that happens, this
+        can be enabled, and the other call to build_t_desc removed.  */
+      /* Kick out the type descriptor before writing out the vtable.  */
+      if (flag_rtti)
+       build_t_desc (DECL_CONTEXT (vars), 1);
+#endif
+
       /* Write it out.  */
       mark_vtable_entries (vars);
       if (TREE_TYPE (DECL_INITIAL (vars)) == 0)
@@ -2651,19 +2676,22 @@ walk_vtables (typedecl_fn, vardecl_fn)
     {
       register tree type = TREE_TYPE (vars);
 
-      if (TREE_CODE (vars) == TYPE_DECL
-         && type != error_mark_node
-         && TYPE_LANG_SPECIFIC (type)
-         && CLASSTYPE_VSIZE (type))
+      if (TREE_CODE (vars) == VAR_DECL && DECL_VIRTUAL_P (vars))
        {
-         if (typedecl_fn) (*typedecl_fn) (prev, vars);
+         if (vardecl_fn) (*vardecl_fn) (prev, vars);
+
+         if (prev && TREE_CHAIN (prev) != vars)
+           continue;
        }
-      else if (TREE_CODE (vars) == VAR_DECL && DECL_VIRTUAL_P (vars))
+      else if (TREE_CODE (vars) == TYPE_DECL
+              && type != error_mark_node
+              && TYPE_LANG_SPECIFIC (type)
+              && CLASSTYPE_VSIZE (type))
        {
-         if (vardecl_fn) (*vardecl_fn) (prev, vars);
+         if (typedecl_fn) (*typedecl_fn) (prev, vars);
        }
-      else
-       prev = vars;
+
+      prev = vars;
     }
 }
 
@@ -2805,6 +2833,31 @@ finish_file ()
   interface_unknown = 1;
   interface_only = 0;
 
+#if 1
+  /* The reason for pushing garbage onto the global_binding_level is to
+     ensure that we can slice out _DECLs which pertain to virtual function
+     tables.  If the last thing pushed onto the global_binding_level was a
+     virtual function table, then slicing it out would slice away all the
+     decls (i.e., we lose the head of the chain).
+
+     There are several ways of getting the same effect, from changing the
+     way that iterators over the chain treat the elements that pertain to
+     virtual function tables, moving the implementation of this code to
+     decl.c (where we can manipulate global_binding_level directly),
+     popping the garbage after pushing it and slicing away the vtable
+     stuff, or just leaving it alone. */
+
+  /* Make last thing in global scope not be a virtual function table.  */
+#if 0 /* not yet, should get fixed properly later */
+  vars = make_type_decl (get_identifier (" @%$#@!"), integer_type_node);
+#else
+  vars = build_decl (TYPE_DECL, get_identifier (" @%$#@!"), integer_type_node);
+#endif
+  DECL_IGNORED_P (vars) = 1;
+  SET_DECL_ARTIFICIAL (vars);
+  pushdecl (vars);
+#endif
+
   /* Walk to mark the inline functions we need, then output them so
      that we can pick up any other tdecls that those routines need. */
   walk_vtables ((void (*)())0, finish_prevtable_vardecl);
@@ -3023,37 +3076,12 @@ finish_file ()
 
   start_time = get_run_time ();
 
-  /* Now delete from the chain of variables all virtual function tables.
-     We output them all ourselves, because each will be treated specially.  */
-
-#if 1
-  /* The reason for pushing garbage onto the global_binding_level is to
-     ensure that we can slice out _DECLs which pertain to virtual function
-     tables.  If the last thing pushed onto the global_binding_level was a
-     virtual function table, then slicing it out would slice away all the
-     decls (i.e., we lose the head of the chain).
-
-     There are several ways of getting the same effect, from changing the
-     way that iterators over the chain treat the elements that pertain to
-     virtual function tables, moving the implementation of this code to
-     decl.c (where we can manipulate global_binding_level directly),
-     popping the garbage after pushing it and slicing away the vtable
-     stuff, or just leaving it alone. */
-
-  /* Make last thing in global scope not be a virtual function table.  */
-#if 0 /* not yet, should get fixed properly later */
-  vars = make_type_decl (get_identifier (" @%$#@!"), integer_type_node);
-#else
-  vars = build_decl (TYPE_DECL, get_identifier (" @%$#@!"), integer_type_node);
-#endif
-  DECL_IGNORED_P (vars) = 1;
-  SET_DECL_ARTIFICIAL (vars);
-  pushdecl (vars);
-#endif
-
   if (flag_handle_signatures)
     walk_sigtables ((void (*)())0, finish_sigtable_vardecl);
 
+  for (fnname = saved_inlines; fnname; fnname = TREE_CHAIN (fnname))
+    import_export_inline (TREE_VALUE (fnname));
+
   /* Now write out inline functions which had their addresses taken and
      which were not declared virtual and which were not declared `extern
      inline'.  */
@@ -3089,7 +3117,7 @@ finish_file ()
                TREE_CHAIN (last) = TREE_CHAIN (place);
                continue;
              }
-           import_export_inline (decl);
+
            if (TREE_PUBLIC (decl)
                || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
                || flag_keep_inline_functions)
@@ -3112,6 +3140,9 @@ finish_file ()
       }
   }
 
+  /* Now delete from the chain of variables all virtual function tables.
+     We output them all ourselves, because each will be treated specially.  */
+
   walk_vtables ((void (*)())0, prune_vtable_vardecl);
 
   for (vars = getdecls (); vars; vars = TREE_CHAIN (vars))
index 215dd17..d7bbff8 100644 (file)
@@ -1142,6 +1142,13 @@ dump_expr (t, nop)
       }
       break;
 
+    case ARRAY_REF:
+      dump_expr (TREE_OPERAND (t, 0), 0);
+      OB_PUTC ('[');
+      dump_expr (TREE_OPERAND (t, 1), 0);
+      OB_PUTC (']');
+      break;
+
     case CONVERT_EXPR:
       dump_unary_op ("+", t, nop);
       break;
index a7dc3d8..338065b 100644 (file)
@@ -264,7 +264,7 @@ fixup_result_decl (decl, result)
          REG_FUNCTION_VALUE_P (real_decl_result) = 1;
          result = real_decl_result;
        }
-      emit_move_insn (result, DECL_RTL (decl));
+      store_expr (decl, result, 0);
       emit_insn (gen_rtx (USE, VOIDmode, result));
     }
 }
@@ -274,9 +274,90 @@ fixup_result_decl (decl, result)
    in some cases.  We cannot use `memory_operand' as a test
    here because on most RISC machines, a variable's address
    is not, by itself, a legitimate address.  */
+
 int
 decl_in_memory_p (decl)
      tree decl;
 {
   return DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == MEM;
 }
+
+/* Expand this initialization inline and see if it's simple enough that
+   it can be done at compile-time.  */
+
+static tree
+extract_aggr_init (decl, init)
+     tree decl, init;
+{
+  return 0;
+}
+
+static tree
+extract_scalar_init (decl, init)
+     tree decl, init;
+{
+  rtx value, insns, insn;
+  extern struct obstack temporary_obstack;
+  tree t = NULL_TREE;
+
+  push_obstacks (&temporary_obstack, &temporary_obstack);
+  start_sequence ();
+  value = expand_expr (init, NULL_RTX, VOIDmode, 0);
+  insns = get_insns ();
+  end_sequence ();
+  reg_scan (insns, max_reg_num (), 0);
+  jump_optimize (insns, 0, 0, 1);
+  pop_obstacks ();
+
+  for (insn = insns; insn; insn = NEXT_INSN (insn))
+    {
+      rtx r, to;
+
+      if (GET_CODE (insn) == NOTE)
+       continue;
+      else if (GET_CODE (insn) != INSN)
+       return 0;
+
+      r = PATTERN (insn);
+      if (GET_CODE (r) != SET)
+       return 0;
+
+      to = XEXP (r, 0);
+
+      if (! (to == value ||
+            (GET_CODE (to) == SUBREG && XEXP (to, 0) == value)))
+       return 0;
+
+      r = XEXP (r, 1);
+
+      switch (GET_CODE (r))
+       {
+       case CONST_INT:
+         t = build_int_2 (XEXP (r, 0), 0);
+         break;
+       default:
+         return 0;
+       }
+    }
+
+  return t; 
+}
+
+int
+extract_init (decl, init)
+     tree decl, init;
+{
+  return 0;
+
+  if (IS_AGGR_TYPE (TREE_TYPE (decl))
+      || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+    init = extract_aggr_init (decl, init);
+  else
+    init = extract_scalar_init (decl, init);
+
+  if (init == NULL_TREE)
+    return 0;
+
+  DECL_INITIAL (decl) = init;
+  return 1;
+}
index 01c5bcb..3737613 100644 (file)
@@ -571,7 +571,7 @@ emit_base_init (t, immediately)
 
       if (init != void_list_node)
        {
-         member = convert_pointer_to (base_binfo, current_class_decl);
+         member = convert_pointer_to_real (base_binfo, current_class_decl);
          expand_aggr_init_1 (base_binfo, 0,
                              build_indirect_ref (member, NULL_PTR), init,
                              BINFO_OFFSET_ZEROP (base_binfo), LOOKUP_NORMAL);
@@ -1980,6 +1980,10 @@ build_offset_ref (cname, name)
              && ((flag_save_memoized_contexts && global_bindings_p ())
                  || ! allocation_temporary_p ()))
            fnfields = copy_list (fnfields);
+
+         for (t = TREE_VALUE (fnfields); t; t = DECL_CHAIN (t))
+           assemble_external (t);
+
          t = build_tree_list (error_mark_node, fnfields);
          TREE_TYPE (t) = build_offset_type (type, unknown_type_node);
          return t;
index 6cbc006..895f269 100644 (file)
@@ -1796,8 +1796,10 @@ cons_up_default_function (type, full_name, kind)
   /* When on-the-fly synthesis works properly, remove the second and third
      conditions here.  */
   if (flag_keep_inline_functions
+#if 0
       || ! flag_no_inline
       || complex
+#endif
       || ! DECL_EXTERNAL (fn))
     {
       struct pending_inline *t;
@@ -2812,7 +2814,13 @@ linenum:
       extract_interface_info ();
 
       c = get_last_nonwhite_on_line ();
-      if (c != EOF)
+      if (c == EOF)
+       {
+         /* Update the name in the top element of input_file_stack.  */
+         if (input_file_stack)
+           input_file_stack->name = input_filename;
+       }
+      else
        {
          put_back (c);
 
index 29b64e6..adbb97e 100644 (file)
@@ -2209,12 +2209,12 @@ synthesize_method (fndecl)
      tree fndecl;
 {
   int nested = (current_function_decl != NULL_TREE);
-  int toplev = (decl_function_context (fndecl) == NULL_TREE);
+  tree context = decl_function_context (fndecl);
   char *f = input_filename;
   tree base = DECL_CLASS_CONTEXT (fndecl);
 
   if (nested)
-    push_cp_function_context (toplev);
+    push_cp_function_context (context);
 
   input_filename = DECL_SOURCE_FILE (fndecl);
   interface_unknown = CLASSTYPE_INTERFACE_UNKNOWN (base);
@@ -2238,8 +2238,19 @@ synthesize_method (fndecl)
     }
 
   finish_function (lineno, 0, nested);
+
+  /* Do we really *want* to inline this function?  */
+  if (DECL_INLINE (fndecl))
+    {
+      /* Turn off DECL_INLINE for the moment so function_cannot_inline_p
+         will check our size.  */
+      DECL_INLINE (fndecl) = 0;
+      if (function_cannot_inline_p (fndecl) == 0)
+       DECL_INLINE (fndecl) = 1;
+    }
+
   input_filename = f;
   extract_interface_info ();
   if (nested)
-    pop_cp_function_context (toplev);
+    pop_cp_function_context (context);
 }
index d9430ec..d8d7eb8 100644 (file)
@@ -402,8 +402,12 @@ any_id:
        ;
 
 extern_lang_string:
-         EXTERN_LANG_STRING
+       EXTERN_LANG_STRING
                { push_lang_context ($1); }
+       | extern_lang_string EXTERN_LANG_STRING
+               { if (current_lang_name != $2)
+                   cp_error ("use of linkage spec `%D' is different from previous spec `%D'", $2, current_lang_name);
+                 pop_lang_context (); push_lang_context ($2); }
        ;
 
 template_header:
@@ -1725,7 +1729,7 @@ object:     primary '.'
        ;
 
 setattrs: /* empty */
-               { prefix_attributes = $<ttype>0; }
+               { prefix_attributes = chainon (prefix_attributes, $<ttype>0); }
        ;
 
 decl:
index 5ac3b63..e05265a 100644 (file)
@@ -1712,6 +1712,8 @@ instantiate_template (tmpl, targ_ptr)
   if (fndecl == error_mark_node)
     goto exit;
 
+  assemble_external (fndecl);
+
   /* If it's a static member fn in the template, we need to change it
      into a FUNCTION_TYPE and chop off its this pointer.  */
   if (TREE_CODE (TREE_TYPE (DECL_RESULT (tmpl))) == METHOD_TYPE
@@ -2059,6 +2061,23 @@ type_unification (tparms, targs, parms, args, nsubsts, subr)
       if (TREE_CODE_CLASS (TREE_CODE (arg)) != 't')
        {
          my_friendly_assert (TREE_TYPE (arg) != NULL_TREE, 293);
+         if (TREE_CODE (arg) == TREE_LIST
+             && TREE_TYPE (arg) == unknown_type_node
+             && TREE_CODE (TREE_VALUE (arg)) == TEMPLATE_DECL)
+           {
+             int nsubsts, ntparms;
+             tree *targs;
+
+             /* Have to back unify here */
+             arg = TREE_VALUE (arg);
+             nsubsts = 0;
+             ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (arg));
+             targs = (tree *) alloca (sizeof (tree) * ntparms);
+             parm = tree_cons (NULL_TREE, parm, NULL_TREE);
+             return type_unification (DECL_TEMPLATE_PARMS (arg), targs,
+                                      TYPE_ARG_TYPES (TREE_TYPE (arg)),
+                                      parm, &nsubsts, 0);
+           }
          arg = TREE_TYPE (arg);
        }
 #endif
@@ -2200,6 +2219,8 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
                    nsubsts);
 
     case REFERENCE_TYPE:
+      if (TREE_CODE (arg) == REFERENCE_TYPE)
+       arg = TREE_TYPE (arg);
       return unify (tparms, targs, ntparms, TREE_TYPE (parm), arg, nsubsts);
 
     case ARRAY_TYPE:
@@ -2242,8 +2263,6 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
        tree t1, t2;
        t1 = TREE_OPERAND (parm, 0);
        t2 = TREE_OPERAND (parm, 1);
-       if (TREE_CODE (t1) != TEMPLATE_CONST_PARM)
-         return 1;
        return unify (tparms, targs, ntparms, t1,
                      fold (build (PLUS_EXPR, integer_type_node, arg, t2)),
                      nsubsts);
@@ -2299,6 +2318,9 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
       if (TREE_CODE (arg) != FUNCTION_TYPE)
        return 1;
      check_args:
+      if (unify (tparms, targs, ntparms, TREE_TYPE (parm),
+                TREE_TYPE (arg), nsubsts))
+       return 1;
       return type_unification (tparms, targs, TYPE_ARG_TYPES (parm),
                               TYPE_ARG_TYPES (arg), nsubsts, 1);
 
index 763d768..712a76f 100644 (file)
@@ -24,6 +24,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "tree.h"
 #include "cp-tree.h"
 #include "flags.h"
+#include "rtl.h"
 
 #define CEIL(x,y) (((x) + (y) - 1) / (y))
 
@@ -826,6 +827,7 @@ layout_basetypes (rec, binfos)
          DECL_FIELD_CONTEXT (decl) = rec;
          DECL_CLASS_CONTEXT (decl) = rec;
          DECL_FCONTEXT (decl) = basetype;
+         DECL_SAVED_INSNS (decl) = NULL_RTX;
          DECL_FIELD_SIZE (decl) = 0;
          DECL_ALIGN (decl) = TYPE_ALIGN (ptr_type_node);
          TREE_CHAIN (decl) = vbase_decls;
index b7f51d2..2467882 100644 (file)
@@ -369,12 +369,24 @@ common_type (t1, t2)
         But ANSI C++ specifies doing this with the qualifiers.
         So I turned it on again.  */
       {
-       tree target = common_type (TYPE_MAIN_VARIANT (TREE_TYPE (t1)),
-                                  TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
+       tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (t1));
+       tree tt2 = TYPE_MAIN_VARIANT (TREE_TYPE (t2));
        int constp
          = TYPE_READONLY (TREE_TYPE (t1)) || TYPE_READONLY (TREE_TYPE (t2));
        int volatilep
          = TYPE_VOLATILE (TREE_TYPE (t1)) || TYPE_VOLATILE (TREE_TYPE (t2));
+       tree target;
+
+       if (tt1 == tt2)
+         target = tt1;
+       else if ((IS_AGGR_TYPE_CODE (TREE_CODE (tt1))
+                 || TREE_CODE (tt1) == OFFSET_TYPE
+                 || TREE_CODE (tt1) == METHOD_TYPE)
+                && TREE_CODE (tt2) == TREE_CODE (tt1))
+         target = common_type (tt1, tt2);
+       else
+         target = void_type_node;
+
        target = cp_build_type_variant (target, constp, volatilep);
        if (code1 == POINTER_TYPE)
          t1 = build_pointer_type (target);
@@ -480,17 +492,18 @@ common_type (t1, t2)
       return build_type_attribute_variant (t1, attributes);
 
     case OFFSET_TYPE:
-      if (TYPE_OFFSET_BASETYPE (t1) == TYPE_OFFSET_BASETYPE (t2)
-         && TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
+      if (TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
        {
-         tree basetype = TYPE_OFFSET_BASETYPE (t1);
-         t1 = build_offset_type (basetype,
-                                   common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
-       }
-      else
-        compiler_error ("common_type called with uncommon member types");
+         tree b1 = TYPE_OFFSET_BASETYPE (t1);
+         tree b2 = TYPE_OFFSET_BASETYPE (t2);
+         tree base;
 
-      /* ... falls through ... */
+         if (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2))
+           return build_type_attribute_variant (t1, attributes);
+         else if (binfo_or_else (b2, b1))
+           return build_type_attribute_variant (t2, attributes);
+       }
+      compiler_error ("common_type called with uncommon member types");
 
     default:
       return build_type_attribute_variant (t1, attributes);
@@ -762,6 +775,17 @@ comp_target_types (ttl, ttr, nptrs)
   if (ttl == ttr)
     return 1;
 
+  if (TREE_CODE (ttl) == VOID_TYPE
+      && TREE_CODE (ttr) != FUNCTION_TYPE
+      && TREE_CODE (ttr) != METHOD_TYPE
+      && TREE_CODE (ttr) != OFFSET_TYPE)
+    return 1;
+  if (TREE_CODE (ttr) == VOID_TYPE
+      && TREE_CODE (ttl) != FUNCTION_TYPE
+      && TREE_CODE (ttl) != METHOD_TYPE
+      && TREE_CODE (ttl) != OFFSET_TYPE)
+    return -1;
+  
   if (TREE_CODE (ttr) != TREE_CODE (ttl))
     return 0;
 
@@ -1680,6 +1704,7 @@ build_component_ref (datum, component, basetype_path, protect)
                          my_friendly_assert (datum != error_mark_node, 310);
                          fndecl = build_vfn_ref (&addr, datum, DECL_VINDEX (fndecl));
                        }
+                     assemble_external (fndecl);
                      return fndecl;
                    }
                  if (access == access_protected)
@@ -1692,7 +1717,12 @@ build_component_ref (datum, component, basetype_path, protect)
                {
                  /* Just act like build_offset_ref, since the object does
                      not matter unless we're actually calling the function.  */
-                 tree t = build_tree_list (error_mark_node, fndecls);
+                 tree t;
+
+                 for (t = TREE_VALUE (fndecls); t; t = DECL_CHAIN (t))
+                   assemble_external (t);
+
+                 t = build_tree_list (error_mark_node, fndecls);
                  TREE_TYPE (t) = build_offset_type (basetype,
                                                     unknown_type_node);
                  return t;
@@ -1779,6 +1809,13 @@ build_indirect_ref (ptr, errorstring)
   if (ptr == current_class_decl)
     return C_C_D;
 
+  ptr = build_expr_type_conversion (WANT_POINTER, pointer, 1);
+  if (ptr)
+    {
+      pointer = ptr;
+      type = TREE_TYPE (pointer);
+    }
+
   if (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type) == REFERENCE_TYPE)
     {
       if (TREE_CODE (pointer) == ADDR_EXPR
@@ -2821,6 +2858,10 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
      Zero means they need to be converted to RESULT_TYPE.  */
   int converted = 0;
 
+  /* Nonzero means create the expression with this type, rather than
+     RESULT_TYPE.  */
+  tree build_type = 0;
+
   /* Nonzero means after finally constructing the expression
      give it this type.  Otherwise, give it type RESULT_TYPE.  */
   tree final_type = 0;
@@ -3064,8 +3105,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
 
     case EQ_EXPR:
     case NE_EXPR:
-      result_type = boolean_type_node;
-      converted = 1;
+      build_type = boolean_type_node; 
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
          && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
        short_compare = 1;
@@ -3073,33 +3113,9 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
        {
          register tree tt0 = TYPE_MAIN_VARIANT (TREE_TYPE (type0));
          register tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (type1));
-         /* Anything compares with void *.  void * compares with anything.
-            Otherwise, the targets must be the same.  */
-         if (tt0 != tt1 && TREE_CODE (tt0) == RECORD_TYPE
-             && TREE_CODE (tt1) == RECORD_TYPE)
-           {
-             tree base = common_base_type (tt0, tt1);
-             if (base == NULL_TREE)
-               cp_pedwarn ("comparison of distinct object pointer types `%T' and `%T'", type0, type1);
-             else if (base == error_mark_node)
-               {
-                 cp_error ("comparison of pointer types `%T' and `%T' requires conversion to ambiguous supertype", type0, type1);
-                 return error_mark_node;
-               }
-             else
-               {
-                 if (integer_zerop (op0))
-                   op0 = null_pointer_node;
-                 else
-                   op0 = convert_pointer_to (base, op0);
-                 if (integer_zerop (op1))
-                   op1 = null_pointer_node;
-                 else
-                   op1 = convert_pointer_to (base, op1);
-               }
-           }
-         else if (comp_target_types (type0, type1, 1))
-           ;
+
+         if (comp_target_types (type0, type1, 1))
+           result_type = common_type (type0, type1);
          else if (tt0 == void_type_node)
            {
              if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE
@@ -3225,10 +3241,11 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
        {
          return build_binary_op (code, op1, op0, 1);
        }
-      else
-       /* If args are not valid, clear out RESULT_TYPE
-          to cause an error message later.  */
-       result_type = 0;
+
+      type0 = TREE_TYPE (op0);
+      type1 = TREE_TYPE (op1);
+      if (result_type == NULL_TREE)
+       result_type = type0;
       break;
 
     case MAX_EXPR:
@@ -3239,8 +3256,12 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
          if (! comp_target_types (type0, type1, 1))
-           cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
-                       type0, type1);
+           {
+             cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
+                         type0, type1);
+             result_type = ptr_type_node;
+           }
+#if 0
          else if ((TYPE_SIZE (TREE_TYPE (type0)) != 0)
                   != (TYPE_SIZE (TREE_TYPE (type1)) != 0))
            cp_pedwarn ("comparison of %scomplete and %scomplete pointers",
@@ -3250,15 +3271,20 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
          else if (pedantic
                   && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
            pedwarn ("ANSI C++ forbids ordered comparisons of pointers to functions");
-         result_type = common_type (type0, type1);
+#endif
+         else
+           result_type = common_type (type0, type1);
        }
+
+      if (result_type == NULL_TREE)
+       result_type = type0;
       break;
 
     case LE_EXPR:
     case GE_EXPR:
     case LT_EXPR:
     case GT_EXPR:
-      result_type = boolean_type_node;
+      build_type = boolean_type_node;
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
           && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
        short_compare = 1;
@@ -3267,6 +3293,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
          if (! comp_target_types (type0, type1, 1))
            cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
                        type0, type1);
+#if 0
          else if ((TYPE_SIZE (TREE_TYPE (type0)) != 0)
                   != (TYPE_SIZE (TREE_TYPE (type1)) != 0))
            cp_pedwarn ("comparison of %scomplete and %scomplete pointers",
@@ -3276,6 +3303,9 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
          else if (pedantic 
                   && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
            pedwarn ("ANSI C++ forbids ordered comparisons of pointers to functions");
+#endif
+         else
+           result_type = common_type (type0, type1);
        }
       else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
               && integer_zerop (op1))
@@ -3299,9 +3329,11 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
            warning ("comparison between pointer and integer");
          op0 = convert (TREE_TYPE (op1), op0);
        }
-      else
-       result_type = 0;
-      converted = 1;
+
+      type0 = TREE_TYPE (op0);
+      type1 = TREE_TYPE (op1);
+      if (result_type == NULL_TREE)
+       result_type = type0;
       break;
     }
 
@@ -3437,7 +3469,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
            = shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
          if (val != 0)
            return convert (boolean_type_node, val);
-         op0 = xop0, op1 = xop1, result_type = boolean_type_node;
+         op0 = xop0, op1 = xop1;
+         converted = 1;
          resultcode = xresultcode;
        }
 
@@ -3544,8 +3577,11 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
        op1 = convert (result_type, op1); 
     }
 
+  if (build_type == NULL_TREE)
+    build_type = result_type;
+
   {
-    register tree result = build (resultcode, result_type, op0, op1);
+    register tree result = build (resultcode, build_type, op0, op1);
     register tree folded;
 
     folded = fold (result);
@@ -6731,11 +6767,22 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
             && TREE_CODE (rhstype) == POINTER_TYPE
             && TREE_CODE (TREE_TYPE (rhstype)) == METHOD_TYPE)
            || integer_zerop (rhs)
-           || TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
+           || TYPE_PTRMEMFUNC_P (rhstype))
           && TYPE_PTRMEMFUNC_P (type))
     {
+      tree ttl = TYPE_PTRMEMFUNC_FN_TYPE (type);
+      tree ttr = (TREE_CODE (rhstype) == POINTER_TYPE ? rhstype
+                   : TYPE_PTRMEMFUNC_FN_TYPE (type));
+      int ctt = comp_target_types (ttl, ttr, 1);
+
+      if (ctt < 0)
+       cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
+                   ttr, ttl);
+      else if (ctt == 0)
+       cp_error ("%s to `%T' from `%T'", errtype, ttl, ttr);
+
       /* compatible pointer to member functions. */
-      return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), rhs, 0);
+      return build_ptrmemfunc (ttl, rhs, 0);
     }
   else if (codel == ERROR_MARK || coder == ERROR_MARK)
     return error_mark_node;