re PR c++/2204 (G++ doesn't check (member) function parameter for abstract-ness.)
[gcc.git] / gcc / cp / typeck2.c
index 5bf6d144cf162ccec5bd0f3791ee56d118d66d19..6e32377c4a35f70c0eae3ed42f8359bb761fed6c 100644 (file)
@@ -26,11 +26,7 @@ Boston, MA 02111-1307, USA.  */
 /* This file is part of the C++ front end.
    It contains routines to build C++ expressions given their operands,
    including computing the types of the result, C and C++ specific error
-   checks, and some optimization.
-
-   There are also routines to build RETURN_STMT nodes and CASE_STMT nodes,
-   and to process initializations in declarations (since they work
-   like a strange sort of assignment).  */
+   checks, and some optimization.  */
 
 #include "config.h"
 #include "system.h"
@@ -118,6 +114,119 @@ readonly_error (tree arg, const char* string, int soft)
     (*fn) ("%s of read-only location", string);
 }
 
+\f
+/* Structure that holds information about declarations whose type was
+   incomplete and we could not check whether it was abstract or not.  */
+
+struct pending_abstract_type GTY((chain_next ("%h.next")))
+{
+  /* Declaration which we are checking for abstractness. It is either
+     a DECL node, or an IDENTIFIER_NODE if we do not have a full
+     declaration available.  */
+  tree decl;
+
+  /* Type which will be checked for abstractness.  */
+  tree type;
+
+  /* Position of the declaration. This is only needed for IDENTIFIER_NODEs,
+     because DECLs already carry locus information.  */
+  location_t locus;
+
+  /* Link to the next element in list.  */
+  struct pending_abstract_type* next;
+};
+
+
+/* Compute the hash value of the node VAL. This function is used by the
+   hash table abstract_pending_vars.  */
+
+static hashval_t
+pat_calc_hash (const void* val)
+{
+  const struct pending_abstract_type* pat = val;
+  return (hashval_t) TYPE_UID (pat->type);
+}
+
+
+/* Compare node VAL1 with the type VAL2. This function is used by the
+   hash table abstract_pending_vars.  */
+
+static int
+pat_compare (const void* val1, const void* val2)
+{
+  const struct pending_abstract_type* pat1 = val1;
+  tree type2 = (tree)val2;
+
+  return (pat1->type == type2);
+}
+
+/* Hash table that maintains pending_abstract_type nodes, for which we still
+   need to check for type abstractness.  The key of the table is the type
+   of the declaration.  */
+static GTY ((param_is (struct pending_abstract_type)))
+htab_t abstract_pending_vars = NULL;
+
+
+/* This function is called after TYPE is completed, and will check if there
+   are pending declarations for which we still need to verify the abstractness
+   of TYPE, and emit a diagnostic (through abstract_virtuals_error) if TYPE
+   turned out to be incomplete.  */
+
+void
+complete_type_check_abstract (tree type)
+{
+  void **slot;
+  struct pending_abstract_type *pat;
+  location_t cur_loc = input_location;
+
+  my_friendly_assert (COMPLETE_TYPE_P (type), 20040620_3);
+
+  if (!abstract_pending_vars)
+    return;
+
+  /* Retrieve the list of pending declarations for this type.  */
+  slot = htab_find_slot_with_hash (abstract_pending_vars, type,
+                                  (hashval_t)TYPE_UID (type), NO_INSERT);
+  if (!slot)
+    return;
+  pat = (struct pending_abstract_type*)*slot;
+  my_friendly_assert (pat, 20040620_2);
+
+  /* If the type is not abstract, do not do anything.  */
+  if (CLASSTYPE_PURE_VIRTUALS (type))
+    {
+      struct pending_abstract_type *prev = 0, *next;
+
+      /* Reverse the list to emit the errors in top-down order.  */
+      for (; pat; pat = next)
+       {
+         next = pat->next;
+         pat->next = prev;
+         prev = pat;
+       }
+      pat = prev;
+
+      /* Go through the list, and call abstract_virtuals_error for each
+       element: it will issue a diagostic if the type is abstract.  */
+      while (pat)
+       {
+         my_friendly_assert (type == pat->type, 20040620_4);
+
+         /* Tweak input_location so that the diagnostic appears at the correct
+           location. Notice that this is only needed if the decl is an
+           IDENTIFIER_NODE, otherwise cp_error_at. */
+         input_location = pat->locus;
+         abstract_virtuals_error (pat->decl, pat->type);
+         pat = pat->next;
+       }
+    }
+
+  htab_clear_slot (abstract_pending_vars, slot);
+
+  input_location = cur_loc;
+}
+
+
 /* If TYPE has abstract virtual functions, issue an error about trying
    to create an object of that type.  DECL is the object declared, or
    NULL_TREE if the declaration is unavailable.  Returns 1 if an error
@@ -129,7 +238,45 @@ abstract_virtuals_error (tree decl, tree type)
   tree u;
   tree tu;
 
-  if (!CLASS_TYPE_P (type) || !CLASSTYPE_PURE_VIRTUALS (type))
+  /* This function applies only to classes. Any other entity can never
+     be abstract.  */
+  if (!CLASS_TYPE_P (type))
+    return 0;
+
+  /* If the type is incomplete, we register it within a hash table,
+     so that we can check again once it is completed. This makes sense
+     only for objects for which we have a declaration or at least a
+     name.  */
+  if (!COMPLETE_TYPE_P (type))
+    {
+      void **slot;
+      struct pending_abstract_type *pat;
+
+      my_friendly_assert (!decl || (DECL_P (decl) 
+                                   || TREE_CODE (decl) == IDENTIFIER_NODE),
+                         20040620_1);
+
+      if (!abstract_pending_vars)
+       abstract_pending_vars = htab_create_ggc (31, &pat_calc_hash, 
+                                               &pat_compare, NULL);
+
+      slot = htab_find_slot_with_hash (abstract_pending_vars, type,
+                                     (hashval_t)TYPE_UID (type), INSERT);
+
+      pat = ggc_alloc (sizeof (struct pending_abstract_type));
+      pat->type = type;
+      pat->decl = decl;
+      pat->locus = ((decl && DECL_P (decl))
+                   ? DECL_SOURCE_LOCATION (decl)
+                   : input_location);
+
+      pat->next = *slot;
+      *slot = pat;
+
+      return 0;
+    }
+
+  if (!CLASSTYPE_PURE_VIRTUALS (type))
     return 0;
 
   if (!TYPE_SIZE (type))
@@ -137,11 +284,6 @@ abstract_virtuals_error (tree decl, tree type)
        CLASSTYPE_PURE_VIRTUALS holds the inline friends.  */
     return 0;
 
-  if (dependent_type_p (type))
-    /* For a dependent type, we do not yet know which functions are pure
-       virtuals.  */
-    return 0;
-
   u = CLASSTYPE_PURE_VIRTUALS (type);
   if (decl)
     {
@@ -164,6 +306,10 @@ abstract_virtuals_error (tree decl, tree type)
       else if (TREE_CODE (decl) == FUNCTION_DECL)
        cp_error_at ("invalid abstract return type for function `%+#D'", 
                     decl);
+      else if (TREE_CODE (decl) == IDENTIFIER_NODE)
+       /* Here we do not have location information, so use error instead
+          of cp_error_at.  */
+       error ("invalid abstract type `%T' for `%E'", type, decl);
       else
        cp_error_at ("invalid abstract type for `%+D'", decl);
     }
@@ -293,13 +439,10 @@ cxx_incomplete_type_error (tree value, tree type)
 
 \f
 /* The recursive part of split_nonconstant_init.  DEST is an lvalue
-   expression to which INIT should be assigned.  INIT is a CONSTRUCTOR.
-   PCODE is a pointer to the tail of a chain of statements being emitted.
-   The return value is the new tail of that chain after new statements
-   are generated.  */
+   expression to which INIT should be assigned.  INIT is a CONSTRUCTOR.  */
 
-static tree *
-split_nonconstant_init_1 (tree dest, tree init, tree *pcode)
+static void
+split_nonconstant_init_1 (tree dest, tree init)
 {
   tree *pelt, elt, type = TREE_TYPE (dest);
   tree sub, code, inner_type = NULL;
@@ -327,28 +470,31 @@ split_nonconstant_init_1 (tree dest, tree init, tree *pcode)
          if (TREE_CODE (value) == CONSTRUCTOR)
            {
              if (array_type_p)
-               sub = build (ARRAY_REF, inner_type, dest, field_index);
+               sub = build (ARRAY_REF, inner_type, dest, field_index,
+                            NULL_TREE, NULL_TREE);
              else
-               sub = build (COMPONENT_REF, inner_type, dest, field_index);
+               sub = build (COMPONENT_REF, inner_type, dest, field_index,
+                            NULL_TREE);
 
-             pcode = split_nonconstant_init_1 (sub, value, pcode);
+             split_nonconstant_init_1 (sub, value);
            }
          else if (!initializer_constant_valid_p (value, inner_type))
            {
              *pelt = TREE_CHAIN (elt);
 
              if (array_type_p)
-               sub = build (ARRAY_REF, inner_type, dest, field_index);
+               sub = build (ARRAY_REF, inner_type, dest, field_index,
+                            NULL_TREE, NULL_TREE);
              else
-               sub = build (COMPONENT_REF, inner_type, dest, field_index);
+               sub = build (COMPONENT_REF, inner_type, dest, field_index,
+                            NULL_TREE);
 
              code = build (MODIFY_EXPR, inner_type, sub, value);
              code = build_stmt (EXPR_STMT, code);
-
-             *pcode = code;
-             pcode = &TREE_CHAIN (code);
+             add_stmt (code);
              continue;
            }
+
          pelt = &TREE_CHAIN (elt);
        }
       break;
@@ -359,15 +505,13 @@ split_nonconstant_init_1 (tree dest, tree init, tree *pcode)
          CONSTRUCTOR_ELTS (init) = NULL;
          code = build (MODIFY_EXPR, type, dest, init);
          code = build_stmt (EXPR_STMT, code);
-         pcode = &TREE_CHAIN (code);
+         add_stmt (code);
        }
       break;
 
     default:
       abort ();
     }
-
-  return pcode;
 }
 
 /* A subroutine of store_init_value.  Splits non-constant static 
@@ -382,10 +526,9 @@ split_nonconstant_init (tree dest, tree init)
 
   if (TREE_CODE (init) == CONSTRUCTOR)
     {
-      code = build_stmt (COMPOUND_STMT, NULL_TREE);
-      split_nonconstant_init_1 (dest, init, &COMPOUND_BODY (code));
-      code = build1 (STMT_EXPR, void_type_node, code);
-      TREE_SIDE_EFFECTS (code) = 1;
+      code = push_stmt_list ();
+      split_nonconstant_init_1 (dest, init);
+      code = pop_stmt_list (code);
       DECL_INITIAL (dest) = init;
       TREE_READONLY (dest) = 0;
     }
@@ -811,7 +954,7 @@ process_init_constructor (tree type, tree init, tree* elts)
              return error_mark_node;
            }
 
-         if (TYPE_BINFO_BASETYPES (type))
+         if (BINFO_BASE_BINFOS (TYPE_BINFO (type)))
            {
              sorry ("initializer list for object of class with base classes");
              return error_mark_node;
@@ -1412,3 +1555,6 @@ require_complete_eh_spec_types (tree fntype, tree decl)
        }
     }
 }
+
+\f
+#include "gt-cp-typeck2.h"