aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/typeck2.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/typeck2.c')
-rw-r--r--gcc/cp/typeck2.c165
1 files changed, 159 insertions, 6 deletions
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 5ddfdd5..6e32377 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -114,6 +114,119 @@ readonly_error (tree arg, const char* string, int soft)
(*fn) ("%s of read-only location", string);
}
+
+/* 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
@@ -125,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))
@@ -133,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)
{
@@ -160,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);
}
@@ -1405,3 +1555,6 @@ require_complete_eh_spec_types (tree fntype, tree decl)
}
}
}
+
+
+#include "gt-cp-typeck2.h"