*/
/**
- * @file tr_inheritance.c
+ * @file
* @brief Check types and entities for correctness.
* @date 29.1.2003
* @author Michael Beck, Goetz Lindenmaier
#include "tv.h"
#include "ircons.h"
-#ifdef NDEBUG
-/*
- * in RELEASE mode, returns ret if the expression expr evaluates to zero
- * in ASSERT mode, asserts the expression expr (and the string string).
- */
-#define ASSERT_AND_RET(expr, string, ret) if (!(expr)) return (ret)
+static void report_error(const char *fmt, ...)
+{
+ va_list ap;
-/*
- * in RELEASE mode, returns ret if the expression expr evaluates to zero
- * in ASSERT mode, executes blk if the expression expr evaluates to zero and asserts expr
- */
-#define ASSERT_AND_RET_DBG(expr, string, ret, blk) if (!(expr)) return (ret)
-#else
-#define ASSERT_AND_RET(expr, string, ret) \
-do { \
- if (opt_do_node_verification == FIRM_VERIFICATION_ON) {\
- assert((expr) && string); } \
- if (!(expr)) { \
- if (opt_do_node_verification == FIRM_VERIFICATION_REPORT) \
- fprintf(stderr, #expr " : " string "\n"); \
- firm_verify_failure_msg = #expr " && " string; \
- return (ret); \
- } \
-} while (0)
-
-#define ASSERT_AND_RET_DBG(expr, string, ret, blk) \
-do { \
- if (!(expr)) { \
- firm_verify_failure_msg = #expr " && " string; \
- if (opt_do_node_verification != FIRM_VERIFICATION_ERROR_ONLY) { blk; } \
- if (opt_do_node_verification == FIRM_VERIFICATION_REPORT) \
- fprintf(stderr, #expr " : " string "\n"); \
- else if (opt_do_node_verification == FIRM_VERIFICATION_ON) { \
- assert((expr) && string); \
- } \
- return (ret); \
- } \
-} while (0)
-
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-
-static const char *firm_verify_failure_msg;
-
-#if 0
-/**
- * Show diagnostic if an entity overwrites another one not
- * in direct superclasses.
- */
-static void show_ent_not_supertp(ir_entity *ent, ir_entity *ovw)
+ fprintf(stderr, "Verify warning: ");
+ va_start(ap, fmt);
+ ir_vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+}
+
+static bool check_class_member(const ir_type *tp, const ir_entity *entity)
{
- ir_type *owner = get_entity_owner(ent);
- ir_type *ov_own = get_entity_owner(ovw);
- size_t i;
-
- fprintf(stderr, "Type verification error:\n");
- ir_fprintf(stderr, "Entity %+F::%+e owerwrites ", owner, ent);
- ir_fprintf(stderr, "Entity %+F::%+e\n", ov_own, ovw);
-
- ir_fprintf(stderr, "Supertypes of %+F:\n", owner);
- for (i = 0; i < get_class_n_supertypes(owner); ++i) {
- ir_type *super = get_class_supertype(owner, i);
- ir_fprintf(stderr, " %+F:\n", super);
+ bool fine = true;
+ if (get_entity_n_overwrites(entity) > get_class_n_supertypes(tp)) {
+ report_error("member %+F of %+F has too many overwrites", entity, tp);
+ fine = false;
}
+ return fine;
}
-#endif
-/**
- * Show diagnostic if an entity overwrites a wrong number of things.
- */
-static void show_ent_overwrite_cnt(ir_entity *ent)
+static bool check_compound_type(const ir_type *tp)
{
- ir_type *owner = get_entity_owner(ent);
+ bool fine = true;
+ bool is_class = is_Class_type(tp);
+ size_t n = get_compound_n_members(tp);
size_t i;
- size_t j;
- size_t k;
- bool found;
- bool show_stp = false;
-
- fprintf(stderr, "Type verification error:\n");
- ir_fprintf(stderr, "Entity %t::%e owerwrites\n", owner, ent);
- for (i = 0; i < get_entity_n_overwrites(ent); ++i) {
- ir_entity *ovw = get_entity_overwrites(ent, i);
- ir_type *ov_own = get_entity_owner(ovw);
- size_t n_supertypes = get_class_n_supertypes(owner);
-
- ir_fprintf(stderr, " %t::%e\n", ov_own, ovw);
- for (k = 0; k < i; ++k) {
- if (ovw == get_entity_overwrites(ent, k)) {
- ir_fprintf(stderr, " ->%t::%e entered more than once\n", ov_own, ovw);
- break;
- }
- }
- found = false;
- for (j = 0; j < n_supertypes; ++j) {
- if (ov_own == get_class_supertype(owner, j)) {
- show_stp = found = true;
- break;
- }
- }
- if (! found)
- ir_fprintf(stderr, " ->%t not in super types of %t\n", ov_own, owner);
- }
+ for (i = 0; i < n; ++i) {
+ ir_entity *member = get_compound_member(tp, i);
+ ir_type *owner;
- if (show_stp) {
- ir_fprintf(stderr, "Supertypes of %t:\n", owner);
- for (i = 0; i < get_class_n_supertypes(owner); ++i) {
- ir_type *super = get_class_supertype(owner, i);
- ir_fprintf(stderr, " %t:\n", super);
+ if (member == NULL) {
+ report_error("%+F has a NULL member\n", tp);
+ fine = false;
+ continue;
+ }
+ owner = get_entity_owner(member);
+ if (owner != tp) {
+ report_error("member %+F of %+F has owner %+F\n", member, tp, owner);
+ fine = false;
+ }
+ if (is_class) {
+ fine &= check_class_member(tp, member);
}
}
+ return fine;
}
-#endif /* #ifndef NDEBUG */
-
-/**
- * Check a class
- */
-static int check_class(ir_type *tp)
+static bool check_array_type(const ir_type *tp)
{
- size_t i, n;
-
- for (i = 0, n = get_class_n_members(tp); i < n; ++i) {
- ir_entity *mem = get_class_member(tp, i);
-
- ASSERT_AND_RET_DBG(
- tp == get_entity_owner(mem),
- "class member with wrong owner",
- error_ent_wrong_owner,
- ir_fprintf(stderr, "Type verification error:\n%+F %+e(owner %+F)\n",tp, mem, get_entity_owner(mem))
- );
- ASSERT_AND_RET_DBG(
- mem,
- "NULL members not allowed",
- error_null_mem,
- ir_fprintf(stderr, "Type verification error:\n%+F member %zu is NULL\n", tp, i)
- );
-
- ASSERT_AND_RET_DBG(
- get_entity_n_overwrites(mem) <= get_class_n_supertypes(tp),
- "wrong number of entity overwrites",
- error_wrong_ent_overwrites,
- show_ent_overwrite_cnt(mem)
- );
-
-#if 0
- {
- size_t j, m;
- /* check if the overwrite relation is flat, i.e. every overwrite
- * is visible in every direct superclass. */
- for (j = 0, m = get_entity_n_overwrites(mem); j < m; ++j) {
- ir_entity *ovw = get_entity_overwrites(mem, j);
- size_t k, n_super;
-
- /* Check whether ovw is member of one of tp's supertypes. If so,
- the representation is correct. */
- for (k = 0, n_super = get_class_n_supertypes(tp); k < n_super; ++k) {
- if (get_class_member_index(get_class_supertype(tp, k), ovw) != INVALID_MEMBER_INDEX) {
- ASSERT_AND_RET_DBG(
- 0,
- "overwrites an entity not contained in direct supertype",
- error_ent_not_cont,
- show_ent_not_supertp(mem, ovw)
- );
- break;
- }
- }
- }
+ bool fine = true;
+ size_t n_dim = get_array_n_dimensions(tp);
+ size_t i;
+
+ for (i = 0; i < n_dim; ++i) {
+ if (!has_array_lower_bound(tp, i) && !has_array_upper_bound(tp, i)) {
+ report_error("missing array bound in %+F in dimension %zu", tp, i);
+ fine = false;
}
-#endif
}
- return 0;
+ return fine;
}
-/**
- * Check an array.
- */
-static int check_array(const ir_type *tp)
+static bool check_type_mode(const ir_type *tp)
{
- size_t i, n_dim = get_array_n_dimensions(tp);
-
- for (i = 0; i < n_dim; ++i) {
- ASSERT_AND_RET_DBG(
- has_array_lower_bound(tp, i) || has_array_upper_bound(tp, i),
- "array bound missing",
- 1,
- ir_fprintf(stderr, "%+F in dimension %zu\n", tp, i)
- );
+ bool fine = true;
+ if (get_type_mode(tp) == NULL) {
+ report_error("type %+F has no mode", tp);
+ fine = false;
}
- return 0;
+ return fine;
}
+static bool check_primitive_type(const ir_type *tp)
+{
+ return check_type_mode(tp);
+}
-/**
- * Check a primitive.
- */
-static int check_primitive(ir_type *tp)
+static bool check_pointer_type(const ir_type *tp)
{
- ASSERT_AND_RET_DBG(
- is_mode(get_type_mode(tp)),
- "Primitive type without mode",
- 1,
- ir_fprintf(stderr, "%+F\n", tp)
- );
- return 0;
+ return check_type_mode(tp);
}
-int check_type(ir_type *tp)
+int check_type(const ir_type *tp)
{
switch (get_type_tpop_code(tp)) {
- case tpo_class:
- return check_class(tp);
- case tpo_array:
- return check_array(tp);
- case tpo_primitive:
- return check_primitive(tp);
- default: break;
+ case tpo_union:
+ case tpo_struct:
+ case tpo_class: return check_compound_type(tp);
+ case tpo_array: return check_array_type(tp);
+ case tpo_primitive: return check_primitive_type(tp);
+ case tpo_pointer: return check_pointer_type(tp);
+ case tpo_enumeration:
+ case tpo_method:
+ case tpo_uninitialized:
+ case tpo_unknown:
+ case tpo_none:
+ case tpo_code:
+ break;
}
- return 0;
+ return true;
}
-/**
- * checks the visited flag
- */
-static int check_visited_flag(ir_graph *irg, ir_node *n)
+static bool check_visited_flag(ir_graph *irg, ir_node *n)
{
- ASSERT_AND_RET_DBG(
- get_irn_visited(n) <= get_irg_visited(irg),
- "Visited flag of node is larger than that of corresponding irg.",
- 0,
- ir_fprintf(stderr, "%+F in %+F\n", n, irg)
- );
- return 1;
+ bool fine = true;
+ if (get_irn_visited(n) > get_irg_visited(irg)) {
+ report_error("visited flag of %+F is larger than that of corresponding irg %+F", n, irg);
+ fine = false;
+ }
+ return fine;
}
-/**
- * helper environment struct for constant_on_wrong_obstack()
- */
typedef struct myenv {
- int res;
ir_graph *irg;
+ bool fine;
} myenv;
-/**
- * called by the walker
- */
static void on_irg_storage(ir_node *n, void *data)
{
myenv *env = (myenv*)data;
/* We also test whether the setting of the visited flag is legal. */
- env->res = node_is_in_irgs_storage(env->irg, n) &&
- check_visited_flag(env->irg, n);
+ env->fine &= node_is_in_irgs_storage(env->irg, n);
+ env->fine &= check_visited_flag(env->irg, n);
}
-/**
- * checks whether a given constant IR node is NOT on the
- * constant IR graph.
- */
-static int constant_on_wrong_irg(ir_node *n)
+static bool constant_on_wrong_irg(ir_node *n)
{
myenv env;
- env.res = 1; /* on right obstack */
- env.irg = get_const_code_irg();
+ env.fine = true;
+ env.irg = get_const_code_irg();
irg_walk(n, on_irg_storage, NULL, (void *)&env);
- return ! env.res;
+ return env.fine;
}
-static int initializer_constant_on_wrong_irg(ir_initializer_t *initializer)
+static bool initializer_constant_on_wrong_irg(const ir_initializer_t *initializer)
{
switch (get_initializer_kind(initializer)) {
case IR_INITIALIZER_NULL:
case IR_INITIALIZER_CONST:
return constant_on_wrong_irg(get_initializer_const_value(initializer));
case IR_INITIALIZER_COMPOUND: {
- size_t i, n = get_initializer_compound_n_entries(initializer);
+ bool fine = true;
+ size_t n = get_initializer_compound_n_entries(initializer);
+ size_t i;
for (i = 0; i < n; ++i) {
- ir_initializer_t *sub
+ const ir_initializer_t *sub
= get_initializer_compound_value(initializer, i);
- if (initializer_constant_on_wrong_irg(sub))
- return 1;
+ fine &= initializer_constant_on_wrong_irg(sub);
}
- return 0;
+ return fine;
}
}
- panic("invalid initializer in initializer_on_wrong_irg");
+ panic("invalid initializer");
}
-/**
- * Check if constants node are NOT on the constant IR graph.
- *
- * @return NON-zero if an entity initializer constant is NOT on
- * the current_ir_graph's obstack.
- */
-static int constants_on_wrong_irg(ir_entity *ent)
+static bool constants_on_wrong_irg(const ir_entity *ent)
{
if (ent->initializer != NULL) {
return initializer_constant_on_wrong_irg(ent->initializer);
- } else if (entity_has_compound_ent_values(ent)) {
- size_t i, n;
- for (i = 0, n = get_compound_ent_n_values(ent); i < n; ++i) {
- if (constant_on_wrong_irg(get_compound_ent_value(ent, i)))
- return 1;
- }
}
- return 0;
+ return true;
}
-int check_entity(ir_entity *ent)
+static bool check_external_linkage(const ir_entity *entity, ir_linkage linkage,
+ const char *linkage_name)
{
- ir_type *tp = get_entity_type(ent);
-
- current_ir_graph = get_const_code_irg();
- ASSERT_AND_RET_DBG(
- constants_on_wrong_irg(ent) == 0,
- "Contants placed on wrong IRG",
- error_const_on_wrong_irg,
- ir_fprintf(stderr, "%+e not on %+F\n", ent, current_ir_graph)
- );
-
- /* Originally, this test assumed, that only method entities have
- pecularity_inherited. As I changed this, I have to test for method type
- before doing the test. */
- if (get_entity_peculiarity(ent) == peculiarity_existent
- && is_method_entity(ent)) {
-
- ir_entity *impl = get_SymConst_entity(get_atomic_ent_value(ent));
- ASSERT_AND_RET_DBG(
- impl != NULL,
- "inherited method entities must have constant pointing to existent entity.",
- error_inherited_ent_without_const,
- ir_fprintf(stderr, "%+e points to %+e\n", ent, impl)
- );
+ bool fine = true;
+ if ((get_entity_linkage(entity) & linkage) == 0)
+ return true;
+ if (get_entity_visibility(entity) != ir_visibility_external) {
+ report_error("entity %+F has IR_LINKAGE_%s but is not externally visible", entity, linkage_name);
+ fine = false;
+ }
+ if (!entity_has_definition(entity)) {
+ report_error("entity %+F has IR_LINKAGE_%s but is just a declaration", entity, linkage_name);
+ fine = false;
+ }
+ return fine;
+}
+
+int check_entity(const ir_entity *entity)
+{
+ bool fine = true;
+ ir_type *tp = get_entity_type(entity);
+ ir_linkage linkage = get_entity_linkage(entity);
+
+ fine &= constants_on_wrong_irg(entity);
+
+ if (is_method_entity(entity)) {
+ ir_graph *irg = get_entity_irg(entity);
+ if (irg != NULL) {
+ ir_entity *irg_entity = get_irg_entity(irg);
+ if (irg_entity != entity) {
+ report_error("entity(%+F)->irg->entity(%+F) relation invalid",
+ entity, irg_entity);
+ fine = false;
+ }
+ }
+ if (get_entity_peculiarity(entity) == peculiarity_existent) {
+ ir_entity *impl = get_SymConst_entity(get_atomic_ent_value(entity));
+ if (impl == NULL) {
+ report_error("inherited method entity %+F must have constant pointing to existent entity.", entity);
+ fine = false;
+ }
+ }
}
- if (is_atomic_entity(ent) && ent->initializer != NULL) {
+ if (linkage & IR_LINKAGE_NO_CODEGEN) {
+ if (!is_method_entity(entity)) {
+ report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but is not a function", entity);
+ fine = false;
+ } else if (get_entity_irg(entity) == NULL) {
+ report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but has no ir-graph anyway", entity);
+ fine = false;
+ }
+ if (get_entity_visibility(entity) != ir_visibility_external) {
+ report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but is not externally visible", entity);
+ fine = false;
+ }
+ }
+ check_external_linkage(entity, IR_LINKAGE_WEAK, "WEAK");
+ check_external_linkage(entity, IR_LINKAGE_GARBAGE_COLLECT,
+ "GARBAGE_COLLECT");
+ check_external_linkage(entity, IR_LINKAGE_MERGE, "MERGE");
+
+ if (is_atomic_entity(entity) && entity->initializer != NULL) {
ir_mode *mode = NULL;
- ir_initializer_t *initializer = ent->initializer;
+ ir_initializer_t *initializer = entity->initializer;
switch (initializer->kind) {
case IR_INITIALIZER_CONST:
mode = get_irn_mode(get_initializer_const_value(initializer));
case IR_INITIALIZER_COMPOUND:
break;
}
- ASSERT_AND_RET_DBG(
- mode == NULL || mode == get_type_mode(tp),
- "Mode of constant in entity must match type.",
- error_ent_const_mode,
- ir_fprintf(stderr, "%+e, type %+F(%+F)\n",
- ent, tp, get_type_mode(tp))
- );
+ if (mode != NULL && mode != get_type_mode(tp)) {
+ report_error("initializer of entity %+F has wrong mode.", entity);
+ fine = false;
+ }
}
- return no_error;
+ return fine;
}
-/*
- * check types and entities
- */
static void check_tore(type_or_ent tore, void *env)
{
- int *res = (int*)env;
- assert(tore.ent);
+ bool *fine = (bool*)env;
+
if (is_type(tore.typ)) {
- *res = check_type(tore.typ);
+ *fine &= check_type(tore.typ);
} else {
assert(is_entity(tore.ent));
- *res = check_entity(tore.ent);
+ *fine &= check_entity(tore.ent);
}
}
int tr_verify(void)
{
- static ident *empty = NULL;
- int res = no_error;
+ bool fine = true;
ir_type *constructors;
ir_type *destructors;
ir_type *thread_locals;
size_t i, n;
ir_segment_t s;
- if (empty == NULL)
- empty = new_id_from_chars("", 0);
-
- type_walk(check_tore, NULL, &res);
+ type_walk(check_tore, NULL, &fine);
for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
const ir_type *type = get_segment_type(s);
size_t e;
for (e = 0; e < get_compound_n_members(type); ++e) {
ir_entity *entity = get_compound_member(type, e);
- ASSERT_AND_RET(get_entity_ld_ident(entity) != NULL ||
- get_entity_visibility(entity) == ir_visibility_private,
- "segment members must have a name or visibility_private",
- 1);
+ if (get_entity_ld_ident(entity) == NULL &&
+ get_entity_visibility(entity) != ir_visibility_private) {
+ report_error("public segment member %+F has no name",
+ entity);
+ fine = false;
+ }
}
}
constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
for (i = 0, n = get_compound_n_members(constructors); i < n; ++i) {
const ir_entity *entity = get_compound_member(constructors, i);
- ASSERT_AND_RET(get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER,
- "entity without LINKAGE_HIDDEN_USER in constructors is pointless",
- 1);
+ if ((get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER) == 0) {
+ report_error("entity %+F in constructors without LINKAGE_HIDDEN_USER",
+ entity);
+ fine = false;
+ }
/* Mach-O doesn't like labels in this section */
- ASSERT_AND_RET(get_entity_ld_ident(entity),
- "entity in constructors should have ld_ident=''", 1);
+ if (get_entity_ld_name(entity)[0] != '\0') {
+ report_error("entity %+F in constructors must not have an ld_name",
+ entity);
+ fine = false;
+ }
}
destructors = get_segment_type(IR_SEGMENT_DESTRUCTORS);
for (i = 0, n = get_compound_n_members(destructors); i < n; ++i) {
const ir_entity *entity = get_compound_member(destructors, i);
- ASSERT_AND_RET(get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER,
- "entity without LINKAGE_HIDDEN_USER in destructors is pointless",
- 1);
+ if ((get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER) == 0) {
+ report_error("entity %+F in destructors without LINKAGE_HIDDEN_USER",
+ entity);
+ fine = false;
+ }
/* Mach-O doesn't like labels in this section */
- ASSERT_AND_RET(get_entity_ld_ident(entity),
- "entity in destructors should have ld_ident=''", 1);
+ if (get_entity_ld_name(entity)[0] != '\0') {
+ report_error("entity %+F in destructors must not have an ld_name",
+ entity);
+ fine = false;
+ }
}
thread_locals = get_segment_type(IR_SEGMENT_THREAD_LOCAL);
for (i = 0, n = get_compound_n_members(thread_locals); i < n; ++i) {
const ir_entity *entity = get_compound_member(thread_locals, i);
/* this is odd and should not be allowed I think */
- ASSERT_AND_RET(!is_method_entity(entity),
- "method in THREAD_LOCAL segment", 1);
- ASSERT_AND_RET(! (get_entity_linkage(entity) & IR_LINKAGE_CONSTANT),
- "thread locals must not be constant", 1);
+ if (is_method_entity(entity)) {
+ report_error("method %+F in thread local segment");
+ fine = false;
+ }
+ if (get_entity_linkage(entity) & IR_LINKAGE_CONSTANT) {
+ report_error("entity %+F in thread local segment is constant");
+ fine = false;
+ }
}
- return res;
+ return fine;
}