From 494c1e6b9486fa418db881e843d0b1b5f92f2ac0 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 26 Mar 2024 22:06:39 +0000 Subject: [PATCH] Improve checking for incomplete type declarations --- lib/std.19/reflection.vhdl | 53 ++++++++++++++---------- src/common.c | 1 + src/diag.c | 3 ++ src/lower.c | 12 ++---- src/names.c | 19 ++++++--- src/parse.c | 6 +++ src/sem.c | 76 +++++++++++++++++++++++++--------- src/vcode.c | 16 ++++--- src/vcode.h | 9 ++-- test/lower/vunit4.vhd | 8 ++-- test/parse/names.vhd | 2 +- test/sem/incomplete.vhd | 54 ++++++++++++++++++++++++ test/sem/record.vhd | 7 +++- test/test_sem.c | 85 +++++++++++++++++++++++++------------- 14 files changed, 246 insertions(+), 105 deletions(-) create mode 100644 test/sem/incomplete.vhd diff --git a/lib/std.19/reflection.vhdl b/lib/std.19/reflection.vhdl index f8a005fc..1fa71118 100644 --- a/lib/std.19/reflection.vhdl +++ b/lib/std.19/reflection.vhdl @@ -25,11 +25,15 @@ package REFLECTION is type INDEX_VECTOR is array(DIMENSION range <>) of INDEX; -- Incomplete type declarations - type VALUE_MIRROR; - type SUBTYPE_MIRROR; + type VALUE_MIRROR_PT; + type VALUE_MIRROR is access VALUE_MIRROR_PT; + type SUBTYPE_MIRROR_PT; + type SUBTYPE_MIRROR is access SUBTYPE_MIRROR_PT; -- Enumeration subtype/value mirror - type ENUMERATION_SUBTYPE_MIRROR; + type ENUMERATION_SUBTYPE_MIRROR_PT; + type ENUMERATION_SUBTYPE_MIRROR is access ENUMERATION_SUBTYPE_MIRROR_PT; + type ENUMERATION_VALUE_MIRROR_PT is protected impure function get_subtype_mirror return ENUMERATION_SUBTYPE_MIRROR; impure function to_value_mirror return VALUE_MIRROR; @@ -52,11 +56,12 @@ package REFLECTION is impure function length return POSITIVE_INDEX; impure function ascending return BOOLEAN; end protected; - type ENUMERATION_SUBTYPE_MIRROR is access ENUMERATION_SUBTYPE_MIRROR_PT; -- Integer subtype/value mirror - type INTEGER_SUBTYPE_MIRROR; + type INTEGER_SUBTYPE_MIRROR_PT; + type INTEGER_SUBTYPE_MIRROR is access INTEGER_SUBTYPE_MIRROR_PT; + type INTEGER_VALUE_MIRROR_PT is protected impure function get_subtype_mirror return INTEGER_SUBTYPE_MIRROR; impure function to_value_mirror return VALUE_MIRROR; @@ -77,11 +82,12 @@ package REFLECTION is impure function length return INDEX; impure function ascending return BOOLEAN; end protected; - type INTEGER_SUBTYPE_MIRROR is access INTEGER_SUBTYPE_MIRROR_PT; -- Floating-point subtype/value mirror - type FLOATING_SUBTYPE_MIRROR; + type FLOATING_SUBTYPE_MIRROR_PT; + type FLOATING_SUBTYPE_MIRROR is access FLOATING_SUBTYPE_MIRROR_PT; + type FLOATING_VALUE_MIRROR_PT is protected impure function get_subtype_mirror return FLOATING_SUBTYPE_MIRROR; impure function to_value_mirror return VALUE_MIRROR; @@ -101,11 +107,12 @@ package REFLECTION is impure function high return FLOATING_VALUE_MIRROR; impure function ascending return BOOLEAN; end protected; - type FLOATING_SUBTYPE_MIRROR is access FLOATING_SUBTYPE_MIRROR_PT; -- Physical subtype/value mirror - type PHYSICAL_SUBTYPE_MIRROR; + type PHYSICAL_SUBTYPE_MIRROR_PT; + type PHYSICAL_SUBTYPE_MIRROR is access PHYSICAL_SUBTYPE_MIRROR_PT; + type PHYSICAL_VALUE_MIRROR_PT is protected impure function get_subtype_mirror return PHYSICAL_SUBTYPE_MIRROR; impure function to_value_mirror return VALUE_MIRROR; @@ -133,11 +140,12 @@ package REFLECTION is impure function length return INDEX; impure function ascending return BOOLEAN; end protected; - type PHYSICAL_SUBTYPE_MIRROR is access PHYSICAL_SUBTYPE_MIRROR_PT; -- Record subtype/value mirror - type RECORD_SUBTYPE_MIRROR; + type RECORD_SUBTYPE_MIRROR_PT; + type RECORD_SUBTYPE_MIRROR is access RECORD_SUBTYPE_MIRROR_PT; + type RECORD_VALUE_MIRROR_PT is protected impure function get_subtype_mirror return RECORD_SUBTYPE_MIRROR; impure function to_value_mirror return VALUE_MIRROR; @@ -158,11 +166,12 @@ package REFLECTION is impure function simple_name return STRING; end protected; - type RECORD_SUBTYPE_MIRROR is access RECORD_SUBTYPE_MIRROR_PT; -- Array subtype/value mirror - type ARRAY_SUBTYPE_MIRROR; + type ARRAY_SUBTYPE_MIRROR_PT; + type ARRAY_SUBTYPE_MIRROR is access ARRAY_SUBTYPE_MIRROR_PT; + type ARRAY_VALUE_MIRROR_PT is protected impure function get_subtype_mirror return ARRAY_SUBTYPE_MIRROR; impure function to_value_mirror return VALUE_MIRROR; @@ -189,11 +198,12 @@ package REFLECTION is impure function length(idx : DIMENSION := 1) return INDEX; impure function ascending(idx : DIMENSION := 1) return BOOLEAN; end protected; - type ARRAY_SUBTYPE_MIRROR is access ARRAY_SUBTYPE_MIRROR_PT; -- Access subtype/value mirror - type ACCESS_SUBTYPE_MIRROR; + type ACCESS_SUBTYPE_MIRROR_PT; + type ACCESS_SUBTYPE_MIRROR is access ACCESS_SUBTYPE_MIRROR_PT; + type ACCESS_VALUE_MIRROR_PT is protected impure function get_subtype_mirror return ACCESS_SUBTYPE_MIRROR; impure function to_value_mirror return VALUE_MIRROR; @@ -210,11 +220,12 @@ package REFLECTION is impure function simple_name return STRING; impure function designated_subtype return SUBTYPE_MIRROR; end protected; - type ACCESS_SUBTYPE_MIRROR is access ACCESS_SUBTYPE_MIRROR_PT; -- File subtype/value mirror - type FILE_SUBTYPE_MIRROR; + type FILE_SUBTYPE_MIRROR_PT; + type FILE_SUBTYPE_MIRROR is access FILE_SUBTYPE_MIRROR_PT; + type FILE_VALUE_MIRROR_PT is protected impure function get_subtype_mirror return FILE_SUBTYPE_MIRROR; impure function to_value_mirror return VALUE_MIRROR; @@ -230,11 +241,12 @@ package REFLECTION is impure function simple_name return STRING; impure function designated_subtype return SUBTYPE_MIRROR; end protected; - type FILE_SUBTYPE_MIRROR is access FILE_SUBTYPE_MIRROR_PT; -- Protected subtype/value mirror - type PROTECTED_SUBTYPE_MIRROR; + type PROTECTED_SUBTYPE_MIRROR_PT; + type PROTECTED_SUBTYPE_MIRROR is access PROTECTED_SUBTYPE_MIRROR_PT; + type PROTECTED_VALUE_MIRROR_PT is protected impure function get_subtype_mirror return PROTECTED_SUBTYPE_MIRROR; impure function to_value_mirror return VALUE_MIRROR; @@ -246,7 +258,6 @@ package REFLECTION is impure function simple_name return STRING; end protected; - type PROTECTED_SUBTYPE_MIRROR is access PROTECTED_SUBTYPE_MIRROR_PT; -- Type classes and sub-classes @@ -281,7 +292,6 @@ package REFLECTION is impure function simple_name return STRING; end protected; - type SUBTYPE_MIRROR is access SUBTYPE_MIRROR_PT; type VALUE_MIRROR_PT is protected impure function get_value_class return VALUE_CLASS; @@ -298,5 +308,4 @@ package REFLECTION is impure function to_file return FILE_VALUE_MIRROR; impure function to_protected return PROTECTED_VALUE_MIRROR; end protected; - type VALUE_MIRROR is access VALUE_MIRROR_PT; end package REFLECTION; diff --git a/src/common.c b/src/common.c index 21525dad..ec2c0ac9 100644 --- a/src/common.c +++ b/src/common.c @@ -908,6 +908,7 @@ unsigned dimension_of(type_t type) return type_indexes(type); case T_NONE: case T_RECORD: + case T_INCOMPLETE: return 0; case T_INTEGER: case T_REAL: diff --git a/src/diag.c b/src/diag.c index ab476681..4ddbe6bd 100644 --- a/src/diag.c +++ b/src/diag.c @@ -437,6 +437,9 @@ static const struct { { "External names", { [STD_08] = "8.7" } }, { "Port clauses", { [STD_08] = "6.5.6.3" } }, { "Subprogram instantiation declarations", { [STD_08] = "4.4" } }, + { "Incomplete type declarations", { [STD_08] = "5.4.2", [STD_93] = "3.3.1", + [STD_19] = "5.4.2" } }, + }; diag_t *diag_new(diag_level_t level, const loc_t *loc) diff --git a/src/lower.c b/src/lower.c index 1d75c9d8..f388cb9a 100644 --- a/src/lower.c +++ b/src/lower.c @@ -4733,11 +4733,9 @@ static vcode_reg_t lower_attr_prefix(lower_unit_t *lu, tree_t prefix) static vcode_reg_t lower_reflect_attr(lower_unit_t *lu, tree_t expr) { tree_t name = tree_name(expr); + type_t type = tree_type(expr); - type_t type = tree_type(expr), pt = type_designated(type); - assert(type_is_protected(pt)); - - ident_t init_func = type_ident(pt); + ident_t init_func = type_ident(type); vcode_reg_t context_reg = lower_context_for_call(lu, init_func); type_t value_mirror = reflection_type(REFLECT_VALUE_MIRROR); @@ -4754,11 +4752,9 @@ static vcode_reg_t lower_reflect_attr(lower_unit_t *lu, tree_t expr) vcode_reg_t locus = lower_debug_locus(name); if (is_value_mirror) - return emit_reflect_value(init_func, value_reg, context_reg, - locus, bounds_reg); + return emit_reflect_value(value_reg, context_reg, locus, bounds_reg); else - return emit_reflect_subtype(init_func, context_reg, - locus, bounds_reg); + return emit_reflect_subtype(context_reg, locus, bounds_reg); } static vcode_reg_t lower_attr_param(lower_unit_t *lu, tree_t value, diff --git a/src/names.c b/src/names.c index 5cc49a04..48d0a6ed 100644 --- a/src/names.c +++ b/src/names.c @@ -1132,7 +1132,7 @@ static bool is_forward_decl(tree_t decl, tree_t existing) tree_kind_t tkind = tree_kind(decl); tree_kind_t ekind = tree_kind(existing); - if (tkind == T_TYPE_DECL && ekind == T_TYPE_DECL) + if ((tkind == T_TYPE_DECL || tkind == T_PROT_DECL) && ekind == T_TYPE_DECL) return type_kind(tree_type(existing)) == T_INCOMPLETE; else if ((tkind == T_FUNC_BODY && ekind == T_FUNC_DECL) || (tkind == T_PROC_BODY && ekind == T_PROC_DECL)) { @@ -1341,7 +1341,7 @@ type_t resolve_type(nametab_t *tab, type_t incomplete) if (sym != NULL) { for (int i = 0; i < sym->ndecls; i++) { const decl_t *dd = get_decl(sym, i); - if (dd->kind == T_TYPE_DECL) { + if (dd->kind == T_TYPE_DECL || dd->kind == T_PROT_DECL) { type_t def = tree_type(dd->tree); if (type_kind(def) != T_INCOMPLETE && type_eq(def, incomplete)) return def; @@ -2391,14 +2391,14 @@ static void overload_add_candidate(overload_t *o, tree_t d) APUSH(o->candidates, d); } -static type_t get_protected_type(tree_t t) +static type_t get_protected_type(nametab_t *tab, tree_t t) { switch (tree_kind(t)) { case T_ALL: case T_ALIAS: - return get_protected_type(tree_value(t)); + return get_protected_type(tab, tree_value(t)); case T_REF: - return get_protected_type(tree_ref(t)); + return get_protected_type(tab, tree_ref(t)); case T_VAR_DECL: case T_PARAM_DECL: case T_PORT_DECL: @@ -2412,6 +2412,13 @@ static type_t get_protected_type(tree_t t) type = type_designated(type); else if (type_is_protected(type)) return type; + else if (type_is_incomplete(type)) { + type_t next = resolve_type(tab, type); + if (next == type) + return NULL; + + type = next; + } else return NULL; } @@ -2425,7 +2432,7 @@ static void begin_overload_resolution(overload_t *o) { const symbol_t *sym = NULL; if (o->prefix != NULL) { - type_t type = get_protected_type(o->prefix); + type_t type = get_protected_type(o->nametab, o->prefix); if (type != NULL) { scope_t *scope = scope_for_type(o->nametab, type); sym = symbol_for(scope, o->name); diff --git a/src/parse.c b/src/parse.c index f4c0f210..b4e33248 100644 --- a/src/parse.c +++ b/src/parse.c @@ -3274,6 +3274,11 @@ static tree_t p_attribute_name(tree_t prefix) type_t type = prefix_type(prefix); + if (type != NULL && type_kind(type) == T_INCOMPLETE) { + type = resolve_type(nametab, type); + tree_set_type(prefix, type); + } + const bool deref_prefix = !is_type_attribute(kind) && kind != ATTR_REFLECT && type != NULL && type_is_access(type); @@ -6408,6 +6413,7 @@ static tree_t p_protected_type_declaration(ident_t id) tree_t t = tree_new(T_PROT_DECL); tree_set_ident(t, id); tree_set_type(t, type); + tree_set_loc(t, CURRENT_LOC); insert_name(nametab, t, NULL); diff --git a/src/sem.c b/src/sem.c index b339ba1a..d8385090 100644 --- a/src/sem.c +++ b/src/sem.c @@ -49,6 +49,7 @@ static bool sem_check_attr_ref(tree_t t, bool allow_range, nametab_t *tab); static bool sem_check_generic_map(tree_t t, tree_t unit, nametab_t *tab); static bool sem_check_port_map(tree_t t, tree_t unit, nametab_t *tab); static bool sem_check_subtype(tree_t decl, type_t type, nametab_t *tab); +static bool sem_check_incomplete(tree_t t, type_t type); #define sem_error(t, ...) do { \ error_at(t ? tree_loc(t) : NULL , __VA_ARGS__); \ @@ -273,9 +274,6 @@ static bool sem_check_discrete_range(tree_t r, type_t expect, nametab_t *tab) static bool sem_check_constraint(tree_t constraint, type_t base, nametab_t *tab) { - if (base != NULL && type_is_access(base)) - base = type_designated(base); - const constraint_kind_t consk = tree_subkind(constraint); switch (consk) { case C_RANGE: @@ -398,9 +396,13 @@ static bool sem_check_subtype_helper(tree_t decl, type_t type, nametab_t *tab) type_t base = type_base(type); if (type_is_none(base)) return false; + else if (type_is_access(base)) + base = type_designated(base); if (type_is_protected(base)) sem_error(decl, "subtypes may not have protected base types"); + else if (!sem_check_incomplete(decl, type)) + return false; type_t elem = base; const int ncon = type_constraints(type); @@ -666,10 +668,11 @@ static bool sem_check_type_decl(tree_t t, nametab_t *tab) if (type_is_file(elem_type)) sem_error(t, "array %s cannot have element of file type", istr(tree_ident(t))); - - if (type_is_protected(elem_type)) + else if (type_is_protected(elem_type)) sem_error(t, "array %s cannot have element of protected type", istr(tree_ident(t))); + else if (!sem_check_incomplete(t, elem_type)) + return false; const int nindex = type_indexes(type); for (int i = 0; i < nindex; i++) { @@ -857,6 +860,23 @@ static bool sem_check_subtype_decl(tree_t t, nametab_t *tab) return sem_check_subtype_helper(t, type, tab); } +static bool sem_check_incomplete(tree_t t, type_t type) +{ + if (type_is_incomplete(type)) { + diag_t *d = diag_new(DIAG_ERROR, tree_loc(t)); + diag_printf(d, "invalid use of incomplete type %s", type_pp(type)); + diag_hint(d, NULL, "prior to the end of the corresponding full type " + "declaration, an incomplete type may only be used as the " + "designated type of an access type declaration"); + diag_lrm(d, STD_08, "5.4.2"); + diag_emit(d); + + return false; + } + + return true; +} + static bool sem_no_access_file_or_protected(tree_t t, type_t type, const char *what) { // constants, signals, attributes, generics, ports @@ -905,9 +925,8 @@ static bool sem_check_const_decl(tree_t t, nametab_t *tab) return false; else if (type_is_none(type)) return false; - - if (type_is_incomplete(type)) - sem_error(t, "type %s is incomplete", type_pp(type)); + else if (!sem_check_incomplete(t, type)) + return false; if (!sem_no_access_file_or_protected(t, type, "constants")) return false; @@ -975,9 +994,8 @@ static bool sem_check_signal_decl(tree_t t, nametab_t *tab) return false; } } - else if (type_is_incomplete(type)) - sem_error(t, "declaration of signal %s cannot have incomplete type %s", - istr(tree_ident(t)), type_pp(type)); + else if (!sem_check_incomplete(t, type)) + return false; if (!sem_no_access_file_or_protected(t, type, "signals")) return false; @@ -1030,9 +1048,8 @@ static bool sem_check_var_decl(tree_t t, nametab_t *tab) return false; } } - else if (type_is_incomplete(type)) - sem_error(t, "declaration of variable %s cannot have incomplete type %s", - istr(tree_ident(t)), type_pp(type)); + else if (!sem_check_incomplete(t, type)) + return false; if (tree_has_value(t)) { if (type_kind(type) == T_PROTECTED) @@ -1076,6 +1093,8 @@ static bool sem_check_param_decl(tree_t t, nametab_t *tab) if (!sem_check_subtype(t, type, tab)) return false; + else if (!sem_check_incomplete(t, type)) + return false; // See LRM 93 section 3.3 for restrictions @@ -1193,6 +1212,8 @@ static bool sem_check_port_decl(tree_t t, nametab_t *tab) return false; else if (!sem_check_subtype(t, type, tab)) return false; + else if (!sem_check_incomplete(t, type)) + return false; const class_t class = tree_class(t); const port_mode_t mode = tree_subkind(t); @@ -1353,6 +1374,8 @@ static bool sem_check_generic_decl(tree_t t, nametab_t *tab) return false; else if (type_is_none(type)) return false; + else if (!sem_check_incomplete(t, type)) + return false; if (class != C_TYPE) { if (type_is_access(type)) @@ -1384,6 +1407,11 @@ static bool sem_check_generic_decl(tree_t t, nametab_t *tab) static bool sem_check_field_decl(tree_t t) { + type_t type = tree_type(t); + + if (!sem_check_incomplete(t, type)) + return false; + return true; } @@ -1568,6 +1596,8 @@ static bool sem_check_func_result(tree_t t) sem_error(t, "function result subtype may not denote a protected type"); else if (type_is_file(result)) sem_error(t, "function result subtype may not denote a file type"); + else if (!sem_check_incomplete(t, result)) + return false; return true; } @@ -3788,8 +3818,7 @@ static bool sem_check_record_ref(tree_t t, nametab_t *tab) if (type_is_none(value_type)) return false; else if (!type_is_record(value_type)) - sem_error(value, "expected record type but found %s%s", - type_is_incomplete(value_type) ? "incomplete type " : "", + sem_error(value, "expected record type but found %s", type_pp(value_type)); return true; @@ -3841,6 +3870,8 @@ static bool sem_check_array_slice(tree_t t, nametab_t *tab) if (type_is_none(array_type)) return false; + else if (!sem_check_incomplete(t, array_type)) + return false; else if (!type_is_array(array_type)) sem_error(t, "type of slice prefix %s is not an array", type_pp(array_type)); @@ -4109,6 +4140,8 @@ static bool sem_check_attr_ref(tree_t t, bool allow_range, nametab_t *tab) sem_error(name, "prefix does not have LENGTH attribute"); else if (type_is_none(type)) return false; + else if (!sem_check_incomplete(t, type)) + return false; else if (!type_is_array(type) && !(standard() >= STD_19 && type_is_discrete(type))) sem_error(name, "prefix of attribute LENGTH must be an array%s " @@ -4130,7 +4163,11 @@ static bool sem_check_attr_ref(tree_t t, bool allow_range, nametab_t *tab) { type_t type = tree_type(name); - if (!sem_check_dimension_attr(t, tab)) + if (type_is_none(type)) + return false; + else if (!sem_check_incomplete(t, type)) + return false; + else if (!sem_check_dimension_attr(t, tab)) return false; if (!type_is_array(type) && !type_is_scalar(type)) @@ -5933,9 +5970,8 @@ static bool sem_check_new(tree_t t, nametab_t *tab) if (!has_initial && type_is_unconstrained(type)) sem_error(t, "unconstrained array type %s not allowed in allocator " "expression", type_pp(type)); - else if (type_is_incomplete(type)) - sem_error(t, "incomplete type %s found in allocator expression", - type_pp(type)); + else if (!sem_check_incomplete(t, type)) + return false; else if (type_is_protected(type)) { if (has_initial) sem_error(t, "protected type %s cannot have initial value", diff --git a/src/vcode.c b/src/vcode.c index 11cb28a0..5733d28c 100644 --- a/src/vcode.c +++ b/src/vcode.c @@ -2233,8 +2233,7 @@ void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg) case VCODE_OP_REFLECT_SUBTYPE: { col += vcode_dump_reg(op->result); - col += printf(" := %s ", vcode_op_string(op->kind)); - col += printf(" context "); + col += printf(" := %s context ", vcode_op_string(op->kind)); vcode_dump_reg(op->args.items[0]); col += printf(" locus "); col += vcode_dump_reg(op->args.items[1]); @@ -5867,9 +5866,8 @@ void emit_enter_state(vcode_reg_t state) "state must have integer type"); } -vcode_reg_t emit_reflect_value(ident_t ptype, vcode_reg_t value, - vcode_reg_t context, vcode_reg_t locus, - vcode_reg_t bounds) +vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context, + vcode_reg_t locus, vcode_reg_t bounds) { op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE); vcode_add_arg(op, value); @@ -5883,11 +5881,11 @@ vcode_reg_t emit_reflect_value(ident_t ptype, vcode_reg_t value, VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS, "locus argument to reflect value must be a debug locus"); - return (op->result = vcode_add_reg(vtype_access(vtype_context(ptype)))); + return (op->result = vcode_add_reg(vtype_access(vtype_opaque()))); } -vcode_reg_t emit_reflect_subtype(ident_t ptype, vcode_reg_t context, - vcode_reg_t locus, vcode_reg_t bounds) +vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus, + vcode_reg_t bounds) { op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE); vcode_add_arg(op, context); @@ -5900,7 +5898,7 @@ vcode_reg_t emit_reflect_subtype(ident_t ptype, vcode_reg_t context, VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS, "locus argument to reflect value must be a debug locus"); - return (op->result = vcode_add_reg(vtype_access(vtype_context(ptype)))); + return (op->result = vcode_add_reg(vtype_access(vtype_opaque()))); } vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args, diff --git a/src/vcode.h b/src/vcode.h index 9ace6c0c..fa35be9a 100644 --- a/src/vcode.h +++ b/src/vcode.h @@ -514,11 +514,10 @@ void emit_pop_scope(void); void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus); void emit_unreachable(vcode_reg_t locus); void emit_enter_state(vcode_reg_t state); -vcode_reg_t emit_reflect_value(ident_t ptype, vcode_reg_t value, - vcode_reg_t context, vcode_reg_t locus, - vcode_reg_t bounds); -vcode_reg_t emit_reflect_subtype(ident_t ptype, vcode_reg_t context, - vcode_reg_t locus, vcode_reg_t bounds); +vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context, + vcode_reg_t locus, vcode_reg_t bounds); +vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus, + vcode_reg_t bounds); vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args, int nargs); vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right); diff --git a/test/lower/vunit4.vhd b/test/lower/vunit4.vhd index 0b30d2db..94fae3fc 100644 --- a/test/lower/vunit4.vhd +++ b/test/lower/vunit4.vhd @@ -2,16 +2,16 @@ package vunit4 is type rec; type int_ptr is access integer; + type rec is record + x : int_ptr; + end record; + impure function get_rec(n : natural) return rec; end package; package body vunit4 is - type rec is record - x : int_ptr; - end record; - type int_ptr_vec is array (natural range <>) of int_ptr; shared variable v : int_ptr_vec(1 to 5); diff --git a/test/parse/names.vhd b/test/parse/names.vhd index 79ec3a2e..e366fa75 100644 --- a/test/parse/names.vhd +++ b/test/parse/names.vhd @@ -293,7 +293,7 @@ begin p23: process is type typ; - function p23_func(x : typ) return integer; + --function p23_func(x : typ) return integer; (used to be OK) type typ is (a, b, c); function p23_func(x : typ) return integer is -- OK begin diff --git a/test/sem/incomplete.vhd b/test/sem/incomplete.vhd new file mode 100644 index 00000000..462a245d --- /dev/null +++ b/test/sem/incomplete.vhd @@ -0,0 +1,54 @@ +entity incomplete is +end entity; + +architecture test of incomplete is + type t1; + function func1 return t1; -- Error + + type t2; + type t3 is access t2; -- OK + + type t2 is protected + function func2 return integer; + end protected; + + type t2 is protected body + function func2 return integer is + begin + return 42; + end function; + end protected body; + + shared variable v1 : t2; -- OK + constant c1 : integer := v1.func2; -- OK + + procedure proc1 (variable x : inout t3) is + begin + assert x.func2 = 42; -- OK + end procedure; + + type t4 is access t1(1 to 2); -- Error + type t5 is array (natural range <>) of t1; -- Error + + type t6 is record + f : t1; -- Error + end record; + + constant c2 : integer := t1'length; -- Error + constant c3 : integer := t1'left; -- Error + + function func3 (x : t1) return integer; -- Error + + type t7 is access t1; + + procedure proc2 (variable x : inout t7) is + begin + x.all(1 to 3) := x.all(3 to 5); -- Error + end procedure; +begin + b: block is + generic ( g : t1 := 1 ); -- Error + port ( p : t1 := 2 ); -- Error + begin + end block; +end architecture; diff --git a/test/sem/record.vhd b/test/sem/record.vhd index 873d1455..7387f9a0 100644 --- a/test/sem/record.vhd +++ b/test/sem/record.vhd @@ -9,8 +9,6 @@ package p is x, x : integer; end record; - type r3; - type r3 is record -- Error x : r3; end record; @@ -184,4 +182,9 @@ package body p is sub(x.z => 2); -- Error end procedure; + procedure test3 is + variable r : r1 := r1'left; -- Error + begin + end procedure; + end package body; diff --git a/test/test_sem.c b/test/test_sem.c index eaa32d49..929f70e8 100644 --- a/test/test_sem.c +++ b/test/test_sem.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2011-2022 Nick Gasson +// Copyright (C) 2011-2024 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -761,33 +761,34 @@ START_TEST(test_record) const error_t expect[] = { { 9, "duplicate field name X" }, - { 15, "recursive record types are not allowed" }, - { 30, "record field X cannot have unconstrained array type" }, - { 39, "field Z does not have a value" }, - { 40, "does not match type INTEGER of field Y" }, - { 42, "field Y does not have a value" }, - { 43, "record type R1 has no field named Q" }, - { 44, "type of value R1 does not match type INTEGER of" }, - { 47, "field X was already given a value by earlier named choice" }, - { 48, "field X was already given a value by earlier positional choice" }, - { 64, "variable A1 cannot have unconstrained type R1_VEC" }, - { 72, "record type R1 has no field named F" }, - { 82, "record type R1_SUB has no field named Z" }, - { 86, "index constraint cannot be used with non-array type R1" }, - { 106, "record type R1 has no field named Z" }, - { 111, "record field A cannot be of file type" }, - { 124, "record type R8 has no field named ACK" }, + { 13, "no visible declaration for R3" }, + { 28, "record field X cannot have unconstrained array type" }, + { 37, "field Z does not have a value" }, + { 38, "does not match type INTEGER of field Y" }, + { 40, "field Y does not have a value" }, + { 41, "record type R1 has no field named Q" }, + { 42, "type of value R1 does not match type INTEGER of" }, + { 45, "field X was already given a value by earlier named choice" }, + { 46, "field X was already given a value by earlier positional choice" }, + { 62, "variable A1 cannot have unconstrained type R1_VEC" }, + { 70, "record type R1 has no field named F" }, + { 80, "record type R1_SUB has no field named Z" }, + { 84, "index constraint cannot be used with non-array type R1" }, + { 104, "record type R1 has no field named Z" }, + { 109, "record field A cannot be of file type" }, + { 122, "record type R8 has no field named ACK" }, + { 151, "cannot index non-array type UNIT_SPEC_T" }, { 153, "cannot index non-array type UNIT_SPEC_T" }, { 155, "cannot index non-array type UNIT_SPEC_T" }, - { 157, "cannot index non-array type UNIT_SPEC_T" }, - { 166, "association choice must be a field name" }, - { 167, "3 positional associations given but record type R1 only has 2" }, - { 168, "others association must represent at least one element" }, - { 169, "range association invalid in record aggregate" }, - { 170, "record type R1 has no field named Z" }, - { 170, "range association invalid in record aggregate" }, - { 174, "no visible declaration for FOO" }, - { 184, "type INTEGER is not a record" }, + { 164, "association choice must be a field name" }, + { 165, "3 positional associations given but record type R1 only has 2" }, + { 166, "others association must represent at least one element" }, + { 167, "range association invalid in record aggregate" }, + { 168, "record type R1 has no field named Z" }, + { 168, "range association invalid in record aggregate" }, + { 172, "no visible declaration for FOO" }, + { 182, "type INTEGER is not a record" }, + { 186, "prefix does not have attribute LEFT" }, { -1, NULL } }; expect_errors(expect); @@ -850,9 +851,9 @@ START_TEST(test_access) { 56, "type mark S does not denote a type or a subtype" }, { 76, "unconstrained array type INT_PTR_ARRAY not allowed" }, { 84, "index constraint cannot be used with non-array type INTEGER" }, - { 90, "variable F cannot have incomplete type FOO" }, + { 90, "invalid use of incomplete type FOO" }, { 97, "cannot determine type of allocator expression from the surro" }, - { 105, "incomplete type A found in allocator expression" }, + { 105, "invalid use of incomplete type A" }, { 111, "prefix of a selected name with suffix ALL must have access " }, { 125, "access type PTP cannot designate protected type" }, { 127, "access type FTP cannot designate file type" }, @@ -3512,6 +3513,33 @@ START_TEST(test_spec2) } END_TEST +START_TEST(test_incomplete) +{ + set_standard(STD_02); + + input_from_file(TESTDIR "/sem/incomplete.vhd"); + + const error_t expect[] = { + { 6, "invalid use of incomplete type T1" }, + { 30, "invalid use of incomplete type T1" }, + { 31, "invalid use of incomplete type T1" }, + { 34, "invalid use of incomplete type T1" }, + { 37, "invalid use of incomplete type T1" }, + { 38, "invalid use of incomplete type T1" }, + { 40, "invalid use of incomplete type T1" }, + { 46, "invalid use of incomplete type T1" }, + { 50, "invalid use of incomplete type T1" }, + { 51, "invalid use of incomplete type T1" }, + { -1, NULL } + }; + expect_errors(expect); + + parse_and_check(T_ENTITY, T_ARCH); + + check_expected_errors(); +} +END_TEST + Suite *get_sem_tests(void) { Suite *s = suite_create("sem"); @@ -3677,6 +3705,7 @@ Suite *get_sem_tests(void) tcase_add_test(tc_core, test_genpack4); tcase_add_test(tc_core, test_lcs2016_16); tcase_add_test(tc_core, test_spec2); + tcase_add_test(tc_core, test_incomplete); suite_add_tcase(s, tc_core); return s; -- 2.39.2