From 2e0d6d5af1b217002f9c9c574e12a2d4a14ea718 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 23 Apr 2022 15:05:53 +0200 Subject: [PATCH 1/6] Allow to attach additional information to typedefs Currently typedefs are just a pointer to a data_type_t. Currently typedefs are implemented by setting the name field of a data_type_t when a typedef of the type is declared. This works mostly, but there are some corner cases that can't be supported. E.g. a typedef of a typedef does not work as it overwrites the name field of the same data_type_t multiple times. Forward typedefs can also not be supported since forward typedefs allow to reference a type before it has been declared. There are also some problems with type identifier references from a higher-level scope if there is a type identifier in the current scope with the same name, but it is declared after the type identifier has been referenced. E.g. in the following x should be a vector fo width 8, but it will be a vector of width 4, because while the right type is used it is elaborated in the wrong scope. ``` localparam A = 8; typedef logic [A-1:0] T; module M; localparam A = 4; T x; typedef int T; endmodule ``` Furthermore typedefs used for the type of ports are elaborated in the wrong scope. To handle these corner case issues introduce a data_type_t for typedefs. Signed-off-by: Lars-Peter Clausen --- PScope.cc | 4 ++-- PScope.h | 3 ++- elab_type.cc | 37 +++++++++++++++++++++++++++---------- lexor.lex | 6 +++--- net_scope.cc | 7 ++++--- netlist.h | 6 +++--- parse.y | 19 +++++++------------ parse_misc.h | 6 ++---- pform.cc | 46 +++++++++++++++++++--------------------------- pform.h | 3 ++- pform_dump.cc | 4 ++-- pform_package.cc | 6 ++++-- pform_types.cc | 10 ++++++++++ pform_types.h | 27 ++++++++++++++++++++------- 14 files changed, 107 insertions(+), 77 deletions(-) diff --git a/PScope.cc b/PScope.cc index e2f3192f2..5d5c2fb75 100644 --- a/PScope.cc +++ b/PScope.cc @@ -51,8 +51,8 @@ PScope::PScope(perm_string n, LexicalScope*parent) PScope::~PScope() { - for(map::iterator it = typedefs.begin(); - it != typedefs.end(); ++it) + for(typedef_map_t::iterator it = typedefs.begin(); it != typedefs.end(); + ++it) delete it->second; } diff --git a/PScope.h b/PScope.h index 6a22ac51f..d76b1c819 100644 --- a/PScope.h +++ b/PScope.h @@ -120,7 +120,8 @@ class LexicalScope { bool has_parameter_port_list; // Defined types in the scope. - std::maptypedefs; + typedef std::map typedef_map_t; + typedef_map_t typedefs; // Named events in the scope. std::mapevents; diff --git a/elab_type.cc b/elab_type.cc index 9c8280c61..42a13ed43 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -43,7 +43,6 @@ ivl_type_t data_type_t::elaborate_type(Design*des, NetScope*scope) { scope = find_scope(des, scope); - ivl_assert(*this, scope); Definitions*use_definitions = scope; map::iterator pos = cache_type_elaborate_.lower_bound(use_definitions); @@ -172,13 +171,8 @@ ivl_type_t parray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const ivl_type_t etype = base_type->elaborate_type(des, scope); if (!etype->packed()) { cerr << this->get_fileline() << " error: Packed array "; - if (!name.nil()) - cerr << "`" << name << "` "; cerr << "base-type `"; - if (base_type->name.nil()) - cerr << *base_type; - else - cerr << base_type->name; + cerr << *base_type; cerr << "` is not packed." << endl; des->errors++; } @@ -385,8 +379,31 @@ NetScope *typeref_t::find_scope(Design *des, NetScope *s) const if (scope) s = des->find_package(scope->pscope_name()); - if (!type->name.nil()) - s = s->find_typedef_scope(des, type); - return s; } + +ivl_type_t typedef_t::elaborate_type(Design *des, NetScope *scope) +{ + if (!data_type.get()) { + cerr << get_fileline() << ": error: Undefined type `" << name << "`." + << endl; + des->errors++; + + // Try to recover + return netvector_t::integer_type(); + } + + // Search upwards from where the type was referenced + scope = scope->find_typedef_scope(des, this); + if (!scope) { + cerr << get_fileline() << ": sorry: " + << "Can not find the scope type defintion `" << name << "`." + << endl; + des->errors++; + + // Try to recover + return netvector_t::integer_type(); + } + + return data_type->elaborate_type(des, scope); +} diff --git a/lexor.lex b/lexor.lex index e5ee90a6a..a479f6096 100644 --- a/lexor.lex +++ b/lexor.lex @@ -369,7 +369,7 @@ TU [munpf] identifier here and interpret it in the package scope. */ if (in_package_scope) { if (rc == IDENTIFIER) { - if (data_type_t*type = pform_test_type_identifier(in_package_scope, yylval.text)) { + if (typedef_t*type = pform_test_type_identifier(in_package_scope, yylval.text)) { yylval.type_identifier.text = yylval.text; yylval.type_identifier.type = type; rc = TYPE_IDENTIFIER; @@ -405,7 +405,7 @@ TU [munpf] /* If this identifier names a previously declared type, then return this as a TYPE_IDENTIFIER instead. */ if (rc == IDENTIFIER && gn_system_verilog()) { - if (data_type_t*type = pform_test_type_identifier(yylloc, yylval.text)) { + if (typedef_t*type = pform_test_type_identifier(yylloc, yylval.text)) { yylval.type_identifier.text = yylval.text; yylval.type_identifier.type = type; rc = TYPE_IDENTIFIER; @@ -426,7 +426,7 @@ TU [munpf] } } if (gn_system_verilog()) { - if (data_type_t*type = pform_test_type_identifier(yylloc, yylval.text)) { + if (typedef_t*type = pform_test_type_identifier(yylloc, yylval.text)) { yylval.type_identifier.text = yylval.text; yylval.type_identifier.type = type; return TYPE_IDENTIFIER; diff --git a/net_scope.cc b/net_scope.cc index 70791f094..77a91bc23 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -232,19 +232,20 @@ NetScope*NetScope::find_import(const Design*des, perm_string name) return 0; } -void NetScope::add_typedefs(const map*typedefs) +void NetScope::add_typedefs(const map*typedefs) { if (!typedefs->empty()) typedefs_ = *typedefs; } -NetScope*NetScope::find_typedef_scope(const Design*des, data_type_t*type) +NetScope*NetScope::find_typedef_scope(const Design*des, const typedef_t*type) { assert(type); NetScope *cur_scope = this; while (cur_scope) { - if (cur_scope->typedefs_.find(type->name) != cur_scope->typedefs_.end()) + auto it = cur_scope->typedefs_.find(type->name); + if (it != cur_scope->typedefs_.end() && it->second == type) return cur_scope; NetScope*import_scope = cur_scope->find_import(des, type->name); if (import_scope) diff --git a/netlist.h b/netlist.h index 28d75c2e1..7ad1454f4 100644 --- a/netlist.h +++ b/netlist.h @@ -940,10 +940,10 @@ class NetScope : public Definitions, public Attrib { void add_imports(const std::map*imports); NetScope*find_import(const Design*des, perm_string name); - void add_typedefs(const std::map*typedefs); + void add_typedefs(const std::map*typedefs); /* Search the scope hierarchy for the scope where 'type' was defined. */ - NetScope*find_typedef_scope(const Design*des, data_type_t*type); + NetScope*find_typedef_scope(const Design*des, const typedef_t*type); /* Parameters exist within a scope, and these methods allow one to manipulate the set. In these cases, the name is the @@ -1268,7 +1268,7 @@ class NetScope : public Definitions, public Attrib { const std::map*imports_; - std::maptypedefs_; + std::maptypedefs_; NetEvent *events_; diff --git a/parse.y b/parse.y index 4b7748057..875749ff4 100644 --- a/parse.y +++ b/parse.y @@ -438,7 +438,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector($1.type); + { class_type_t*tmp = dynamic_cast($1.type->get_data_type()); if (tmp == 0) { yyerror(@1, "Type name \"%s\"is not a predeclared class name.", $1.text); } @@ -2656,7 +2656,7 @@ block_item_decls_opt type_declaration : K_typedef data_type IDENTIFIER dimensions_opt ';' { perm_string name = lex_strings.make($3); - pform_set_typedef(name, $2, $4); + pform_set_typedef(@3, name, $2, $4); delete[]$3; } @@ -2665,12 +2665,7 @@ type_declaration inherited from a different scope. */ | K_typedef data_type TYPE_IDENTIFIER dimensions_opt ';' { perm_string name = lex_strings.make($3.text); - if (pform_test_type_identifier_local(name)) { - yyerror(@3, "error: Typedef identifier \"%s\" is already a type name.", $3.text); - delete $4; - } else { - pform_set_typedef(name, $2, $4); - } + pform_set_typedef(@3, name, $2, $4); delete[]$3.text; } @@ -2682,7 +2677,7 @@ type_declaration perm_string name = lex_strings.make($3); class_type_t*tmp = new class_type_t(name); FILE_NAME(tmp, @3); - pform_set_typedef(name, tmp, NULL); + pform_set_typedef(@3, name, tmp, NULL); delete[]$3; } | K_typedef K_enum IDENTIFIER ';' @@ -2697,7 +2692,7 @@ type_declaration perm_string name = lex_strings.make($2); class_type_t*tmp = new class_type_t(name); FILE_NAME(tmp, @2); - pform_set_typedef(name, tmp, NULL); + pform_set_typedef(@3, name, tmp, NULL); delete[]$2; } diff --git a/parse_misc.h b/parse_misc.h index c20cc0e4e..e9a1477bb 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -89,10 +89,8 @@ extern void lex_in_package_scope(PPackage*pkg); * parser detects typedefs and marks the typedef'ed identifiers as * type names. */ -extern data_type_t* pform_test_type_identifier(const YYLTYPE&loc, const char*txt); -extern data_type_t* pform_test_type_identifier(PPackage*pkg, const char*txt); - -extern bool pform_test_type_identifier_local(perm_string txt); +extern typedef_t* pform_test_type_identifier(const YYLTYPE&loc, const char*txt); +extern typedef_t* pform_test_type_identifier(PPackage*pkg, const char*txt); /* * Test if this identifier is a package name. The pform needs to help diff --git a/pform.cc b/pform.cc index a266ab043..f1602a589 100644 --- a/pform.cc +++ b/pform.cc @@ -858,18 +858,28 @@ void pform_put_enum_type_in_scope(enum_type_t*enum_set) lexical_scope->enum_sets.push_back(enum_set); } -void pform_set_typedef(perm_string name, data_type_t*data_type, std::list*unp_ranges) +void pform_set_typedef(const struct vlltype&loc, perm_string name, + data_type_t*data_type, + std::list*unp_ranges) { if(unp_ranges) data_type = new uarray_type_t(data_type, unp_ranges); - add_local_symbol(lexical_scope, name, data_type); + typedef_t *&td = lexical_scope->typedefs[name]; + if (!td) { + td = new typedef_t(name); + FILE_NAME(td, loc); + add_local_symbol(lexical_scope, name, td); + } - data_type_t*&ref = lexical_scope->typedefs[name]; - - ivl_assert(*data_type, ref == 0); - ref = data_type; - ref->name = name; + if (!td->set_data_type(data_type)) { + cerr << loc << " error: Type identifier `" << name + << "` has already been declared in this scope at " + << td->get_data_type()->get_fileline() << "." + << endl; + error_count++; + delete data_type; + } } void pform_set_type_referenced(const struct vlltype&loc, const char*name) @@ -878,13 +888,13 @@ void pform_set_type_referenced(const struct vlltype&loc, const char*name) check_potential_imports(loc, lex_name, false); } -data_type_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt) +typedef_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt) { perm_string name = lex_strings.make(txt); LexicalScope*cur_scope = lexical_scope; do { - map::iterator cur; + LexicalScope::typedef_map_t::iterator cur; // First look to see if this identifier is imported from // a package. If it is, see if it is a type in that @@ -924,24 +934,6 @@ data_type_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt return 0; } -/* - * The parser uses this function to test if the name is a typedef in - * the current scope. We use this to know if we can override the - * definition because it shadows a containing scope. - */ -bool pform_test_type_identifier_local(perm_string name) -{ - LexicalScope*cur_scope = lexical_scope; - - map::iterator cur; - - cur = cur_scope->typedefs.find(name); - if (cur != cur_scope->typedefs.end()) - return true; - - return false; -} - PECallFunction* pform_make_call_function(const struct vlltype&loc, const pform_name_t&name, const list&parms) diff --git a/pform.h b/pform.h index 928dcf97b..66c28900c 100644 --- a/pform.h +++ b/pform.h @@ -303,7 +303,8 @@ extern void pform_make_elab_task(const struct vlltype&li, perm_string name, const std::list¶ms); -extern void pform_set_typedef(perm_string name, data_type_t*data_type, +extern void pform_set_typedef(const struct vlltype&loc, perm_string name, + data_type_t*data_type, std::list*unp_ranges); extern void pform_set_type_referenced(const struct vlltype&loc, const char*name); diff --git a/pform_dump.cc b/pform_dump.cc index f6bc1c1b3..15c7504e9 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1502,10 +1502,10 @@ void PGenerate::dump(ostream&out, unsigned indent) const void LexicalScope::dump_typedefs_(ostream&out, unsigned indent) const { - typedef map::const_iterator iter_t; + typedef typedef_map_t::const_iterator iter_t; for (iter_t cur = typedefs.begin() ; cur != typedefs.end() ; ++ cur) { out << setw(indent) << "" << "typedef of " << cur->first << ":" << endl; - cur->second->pform_dump(out, indent+4); + cur->second->get_data_type()->pform_dump(out, indent+4); } } diff --git a/pform_package.cc b/pform_package.cc index 9e33f2e4e..a772c26ea 100644 --- a/pform_package.cc +++ b/pform_package.cc @@ -143,10 +143,12 @@ PExpr* pform_package_ident(const struct vlltype&loc, return tmp; } -data_type_t* pform_test_type_identifier(PPackage*pkg, const char*txt) +typedef_t* pform_test_type_identifier(PPackage*pkg, const char*txt) { perm_string use_name = lex_strings.make(txt); - map::const_iterator cur = pkg->typedefs.find(use_name); + LexicalScope::typedef_map_t::const_iterator cur; + + cur = pkg->typedefs.find(use_name); if (cur != pkg->typedefs.end()) return cur->second; diff --git a/pform_types.cc b/pform_types.cc index 56509a54c..5f538b5e7 100644 --- a/pform_types.cc +++ b/pform_types.cc @@ -44,3 +44,13 @@ PNamedItem::SymbolType class_type_t::symbol_type() const { return CLASS; } + +bool typedef_t::set_data_type(data_type_t *t) +{ + if (data_type.get()) + return false; + + data_type.reset(t); + + return true; +} diff --git a/pform_types.h b/pform_types.h index 2ef0585c6..2b0d63779 100644 --- a/pform_types.h +++ b/pform_types.h @@ -162,20 +162,31 @@ class data_type_t : public PNamedItem { virtual SymbolType symbol_type() const; - virtual NetScope *find_scope(Design* des, NetScope *scope) const; - - perm_string name; - private: // Elaborate the type to an ivl_type_s type. virtual ivl_type_t elaborate_type_raw(Design*des, NetScope*scope) const; + virtual NetScope *find_scope(Design* des, NetScope *scope) const; // Keep per-scope elaboration results cached. std::map cache_type_elaborate_; }; +struct typedef_t : public PNamedItem { + explicit typedef_t(perm_string n) : name(n) { }; + + ivl_type_t elaborate_type(Design*des, NetScope*scope); + + bool set_data_type(data_type_t *t); + const data_type_t *get_data_type() const { return data_type.get(); } + +protected: + std::unique_ptr data_type; +public: + perm_string name; +}; + struct typeref_t : public data_type_t { - explicit typeref_t(data_type_t *t, PScope *s = 0) : scope(s), type(t) {} + explicit typeref_t(typedef_t *t, PScope *s = 0) : scope(s), type(t) {} ivl_type_t elaborate_type_raw(Design*des, NetScope*scope) const; NetScope *find_scope(Design* des, NetScope *scope) const; @@ -184,7 +195,7 @@ struct typeref_t : public data_type_t { private: PScope *scope; - data_type_t *type; + typedef_t *type; }; struct void_type_t : public data_type_t { @@ -335,7 +346,7 @@ struct string_type_t : public data_type_t { struct class_type_t : public data_type_t { - inline explicit class_type_t(perm_string n) { name = n; } + inline explicit class_type_t(perm_string n) : name(n) { } void pform_dump(std::ostream&out, unsigned indent) const; void pform_dump_init(std::ostream&out, unsigned indent) const; @@ -370,6 +381,8 @@ struct class_type_t : public data_type_t { ivl_type_t elaborate_type_raw(Design*, NetScope*) const; + perm_string name; + virtual SymbolType symbol_type() const; }; From 8ee9d6b5ead26ae8cf8d8ce7fd6c0494e44846c2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 15 Apr 2022 11:38:08 +0200 Subject: [PATCH 2/6] Detect circular type definitions With forward type declarations it is possible to create a circular type definition where a type resolves to itself. E.g. ``` typedef T1; typedef T1 T2; typedef T2 T1; ``` Flag a type as elaborating when elaboration of the type is started and clear it when elaboration finishes. If the elaboration function is entered again while the flag is still set a circular type has been detected and an error is reported. Signed-off-by: Lars-Peter Clausen --- elab_type.cc | 15 ++++++++++++++- pform_types.h | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/elab_type.cc b/elab_type.cc index 42a13ed43..aeb8e5492 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -49,7 +49,20 @@ ivl_type_t data_type_t::elaborate_type(Design*des, NetScope*scope) if (pos != cache_type_elaborate_.end() && pos->first == use_definitions) return pos->second; - ivl_type_t tmp = elaborate_type_raw(des, scope); + ivl_type_t tmp; + if (elaborating) { + des->errors++; + cerr << get_fileline() << ": error: " + << "Circular type definition found involving `" << *this << "`." + << endl; + // Try to recover + tmp = netvector_t::integer_type(); + } else { + elaborating = true; + tmp = elaborate_type_raw(des, scope); + elaborating = false; + } + cache_type_elaborate_.insert(pos, pair(scope, tmp)); return tmp; } diff --git a/pform_types.h b/pform_types.h index 2b0d63779..509e1d5e2 100644 --- a/pform_types.h +++ b/pform_types.h @@ -167,6 +167,8 @@ class data_type_t : public PNamedItem { virtual ivl_type_t elaborate_type_raw(Design*des, NetScope*scope) const; virtual NetScope *find_scope(Design* des, NetScope *scope) const; + bool elaborating = false; + // Keep per-scope elaboration results cached. std::map cache_type_elaborate_; }; From 699ceb15a5016bf63f0df7ecc2d351b95ca4fa89 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 28 Apr 2022 11:26:20 +0200 Subject: [PATCH 3/6] Elaborate enum type on demand Enum types are currently elaborated in lexical declaration order. With forward typedefs it is possible that a type is referenced before it is declared. To support this elaborate the enum type on demand when it is used. This is similar to what is being done for other types. Signed-off-by: Lars-Peter Clausen --- elab_scope.cc | 27 ++------------------------- elab_type.cc | 33 +++++++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/elab_scope.cc b/elab_scope.cc index a03d4df75..716c3bed4 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -169,34 +169,11 @@ static void collect_scope_specparams(Design*des, NetScope*scope, static void elaborate_scope_enumeration(Design*des, NetScope*scope, enum_type_t*enum_type) { - ivl_type_t base_type; bool rc_flag; - base_type = enum_type->base_type->elaborate_type(des, scope); + enum_type->elaborate_type(des, scope); - const struct netvector_t *vec_type = dynamic_cast(base_type); - - if (!vec_type && !dynamic_cast(base_type)) { - cerr << enum_type->get_fileline() << ": error: " - << "Invalid enum base type `" << *base_type << "`." - << endl; - des->errors++; - } else if (base_type->slice_dimensions().size() > 1) { - cerr << enum_type->get_fileline() << ": error: " - << "Enum type must not have more than 1 packed dimension." - << endl; - des->errors++; - } - - bool integer_flag = false; - if (vec_type) - integer_flag = vec_type->get_isint(); - - netenum_t*use_enum = new netenum_t(base_type, enum_type->names->size(), - integer_flag); - - use_enum->set_line(*enum_type); - scope->add_enumeration_set(enum_type, use_enum); + netenum_t *use_enum = scope->enumeration_for_key(enum_type); size_t name_idx = 0; // Find the enumeration width. diff --git a/elab_type.cc b/elab_type.cc index aeb8e5492..cb0156dfd 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -136,13 +136,34 @@ ivl_type_t class_type_t::elaborate_type_raw(Design*des, NetScope*scope) const * available at the right time. At that time, the netenum_t* object is * stashed in the scope so that I can retrieve it here. */ -ivl_type_t enum_type_t::elaborate_type_raw(Design*, NetScope*scope) const +ivl_type_t enum_type_t::elaborate_type_raw(Design *des, NetScope *scope) const { - ivl_assert(*this, scope); - ivl_type_t tmp = scope->enumeration_for_key(this); - if (tmp == 0 && scope->unit()) - tmp = scope->unit()->enumeration_for_key(this); - return tmp; + ivl_type_t base = base_type->elaborate_type(des, scope); + + const struct netvector_t *vec_type = dynamic_cast(base); + + if (!vec_type && !dynamic_cast(base)) { + cerr << get_fileline() << ": error: " + << "Invalid enum base type `" << *base << "`." + << endl; + des->errors++; + } else if (base->slice_dimensions().size() > 1) { + cerr << get_fileline() << ": error: " + << "Enum type must not have more than 1 packed dimension." + << endl; + des->errors++; + } + + bool integer_flag = false; + if (vec_type) + integer_flag = vec_type->get_isint(); + + netenum_t *type = new netenum_t(base, names->size(), integer_flag); + type->set_line(*this); + + scope->add_enumeration_set(this, type); + + return type; } ivl_type_t vector_type_t::elaborate_type_raw(Design*des, NetScope*scope) const From cdc9629ce76f8c81b79bc30e2b57cf02500f7f93 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 31 Mar 2022 15:08:51 +0200 Subject: [PATCH 4/6] Add support for forward type declarations SystemVerilog supports forward type declarations. This allows to declare a type identifier and use it, e.g. in a signal declaration, before declaring what the actual type is. The type still needs to be fully defined eventually in the same scope as its forward type declaration. E.g. ``` typedef T; T x; typedef int T; ``` The forward type definition can also contain the kind of the type it is going to be. E.g struct, union, class, etc. The LRM calls this the basic type. If the actual type is not of the basic type specified in the forward type declaration this is an error. E.g. ``` typedef struct T; typedef int T; // Error, int is not a struct ``` It is legal to have more than one forward type declaration for the same type name, as long as the basic type is the compatible. It is even legal to have a forward type declaration after the actual type has already been declared. E.g. ``` typedef T; typedef int T; typedef T; ``` Implement support for forward type definitions as part of the new typedef_t. The basic type will be attached to the typedef_t. The compatibility of the basic type for multiple forward type declarations will be checked in the parser. The compatibility of the basic type to the actual type will be checked during elaboration, once the actual type is known. Signed-off-by: Lars-Peter Clausen --- elab_type.cc | 37 +++++++++++++++++- parse.y | 104 ++++++++++++++++++++++--------------------------- pform.cc | 33 +++++++++++++--- pform.h | 4 +- pform_types.cc | 35 +++++++++++++++++ pform_types.h | 15 ++++++- 6 files changed, 161 insertions(+), 67 deletions(-) diff --git a/elab_type.cc b/elab_type.cc index cb0156dfd..695ed5cf6 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -439,5 +439,40 @@ ivl_type_t typedef_t::elaborate_type(Design *des, NetScope *scope) return netvector_t::integer_type(); } - return data_type->elaborate_type(des, scope); + ivl_type_t elab_type = data_type->elaborate_type(des, scope); + if (!elab_type) + return netvector_t::integer_type(); + + bool type_ok = true; + switch (basic_type) { + case ENUM: + type_ok = dynamic_cast(elab_type); + break; + case STRUCT: { + const netstruct_t *struct_type = dynamic_cast(elab_type); + type_ok = struct_type && !struct_type->union_flag(); + break; + } + case UNION: { + const netstruct_t *struct_type = dynamic_cast(elab_type); + type_ok = struct_type && struct_type->union_flag(); + break; + } + case CLASS: + type_ok = dynamic_cast(elab_type); + break; + default: + break; + } + + if (!type_ok) { + cerr << data_type->get_fileline() << " error: " + << "Unexpected type `" << *elab_type << "` for `" << name + << "`. It was forward declared as `" << basic_type + << "` at " << get_fileline() << "." + << endl; + des->errors++; + } + + return elab_type; } diff --git a/parse.y b/parse.y index 875749ff4..a4d427704 100644 --- a/parse.y +++ b/parse.y @@ -464,6 +464,8 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector *dimensions; LexicalScope::lifetime_t lifetime; + + enum typedef_t::basic_type typedef_basic_type; }; %token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL @@ -589,6 +591,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector event_variable label_opt class_declaration_endlabel_opt %type block_identifier_opt +%type identifier_name %type event_variable_list %type list_of_identifiers loop_variables %type list_of_port_identifiers list_of_variable_port_identifiers @@ -646,7 +649,6 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector packed_array_data_type %type ps_type_identifier %type simple_packed_type -%type class_identifier %type struct_union_member %type struct_union_member_list %type struct_data_type @@ -706,6 +708,8 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector compressed_operator +%type typedef_basic_type + %token K_TAND %nonassoc K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ %nonassoc K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ K_NB_TRIGGER @@ -786,15 +790,22 @@ block_identifier_opt /* */ ; class_declaration /* IEEE1800-2005: A.1.2 */ - : K_virtual_opt K_class lifetime_opt class_identifier class_declaration_extends_opt ';' - { pform_start_class_declaration(@2, $4, $5.type, $5.exprs, $3); } + : K_virtual_opt K_class lifetime_opt identifier_name class_declaration_extends_opt ';' + { + perm_string name = lex_strings.make($4); + class_type_t *class_type= new class_type_t(name); + FILE_NAME(class_type, @4); + pform_set_typedef(@4, name, class_type, nullptr); + pform_start_class_declaration(@2, class_type, $5.type, $5.exprs, $3); + } class_items_opt K_endclass { // Process a class. pform_end_class_declaration(@9); } class_declaration_endlabel_opt { // Wrap up the class. - check_end_label(@11, "class", $4->name, $11); + check_end_label(@11, "class", $4, $11); + delete[] $4; } ; @@ -803,33 +814,18 @@ class_constraint /* IEEE1800-2005: A.1.8 */ | constraint_declaration ; -class_identifier - : IDENTIFIER - { // Create a synthetic typedef for the class name so that the - // lexor detects the name as a type. - perm_string name = lex_strings.make($1); - class_type_t*tmp = new class_type_t(name); - FILE_NAME(tmp, @1); - pform_set_typedef(@1, name, tmp, NULL); - delete[]$1; - $$ = tmp; - } - | TYPE_IDENTIFIER - { class_type_t*tmp = dynamic_cast($1.type->get_data_type()); - if (tmp == 0) { - yyerror(@1, "Type name \"%s\"is not a predeclared class name.", $1.text); - } - delete[]$1.text; - $$ = tmp; - } + // This is used in places where a new type can be declared or an existig type + // is referenced. E.g. typedefs. +identifier_name + : IDENTIFIER { $$ = $1; } + | TYPE_IDENTIFIER { $$ = $1.text; } ; /* The endlabel after a class declaration is a little tricky because the class name is detected by the lexor as a TYPE_IDENTIFIER if it does indeed match a name. */ class_declaration_endlabel_opt - : ':' TYPE_IDENTIFIER { $$ = $2.text; } - | ':' IDENTIFIER { $$ = $2; } + : ':' identifier_name { $$ = $2; } | { $$ = 0; } ; @@ -2651,51 +2647,43 @@ block_item_decls_opt | { $$ = false; } ; + /* We need to handle K_enum separately because + * `typedef enum ` can either be the start of a enum forward + * declaration or a enum type declaration with a type identifier as its base + * type. And this abmiguity can not be resolved if we reduce the K_enum to + * typedef_basic_type. */ +typedef_basic_type + : K_struct { $$ = typedef_t::STRUCT; } + | K_union { $$ = typedef_t::UNION; } + | K_class { $$ = typedef_t::CLASS; } + ; + /* Type declarations are parsed here. The rule actions call pform functions that add the declaration to the current lexical scope. */ type_declaration - : K_typedef data_type IDENTIFIER dimensions_opt ';' + : K_typedef data_type identifier_name dimensions_opt ';' { perm_string name = lex_strings.make($3); pform_set_typedef(@3, name, $2, $4); delete[]$3; } - /* If the IDENTIFIER already is a typedef, it is possible for this - code to override the definition, but only if the typedef is - inherited from a different scope. */ - | K_typedef data_type TYPE_IDENTIFIER dimensions_opt ';' - { perm_string name = lex_strings.make($3.text); - pform_set_typedef(@3, name, $2, $4); - delete[]$3.text; - } - /* These are forward declarations... */ - | K_typedef K_class IDENTIFIER ';' - { // Create a synthetic typedef for the class name so that the - // lexor detects the name as a type. - perm_string name = lex_strings.make($3); - class_type_t*tmp = new class_type_t(name); - FILE_NAME(tmp, @3); - pform_set_typedef(@3, name, tmp, NULL); - delete[]$3; - } - | K_typedef K_enum IDENTIFIER ';' - { yyerror(@1, "sorry: Enum forward declarations not supported yet."); } - | K_typedef K_struct IDENTIFIER ';' - { yyerror(@1, "sorry: Struct forward declarations not supported yet."); } - | K_typedef K_union IDENTIFIER ';' - { yyerror(@1, "sorry: Union forward declarations not supported yet."); } - | K_typedef IDENTIFIER ';' - { // Create a synthetic typedef for the class name so that the - // lexor detects the name as a type. - perm_string name = lex_strings.make($2); - class_type_t*tmp = new class_type_t(name); - FILE_NAME(tmp, @2); - pform_set_typedef(@3, name, tmp, NULL); + | K_typedef identifier_name ';' + { perm_string name = lex_strings.make($2); + pform_forward_typedef(@2, name, typedef_t::ANY); delete[]$2; } - + | K_typedef typedef_basic_type identifier_name ';' + { perm_string name = lex_strings.make($3); + pform_forward_typedef(@3, name, $2); + delete[]$3; + } + | K_typedef K_enum identifier_name ';' + { perm_string name = lex_strings.make($3); + pform_forward_typedef(@3, name, typedef_t::ENUM); + delete[]$3; + } | K_typedef error ';' { yyerror(@2, "error: Syntax error in typedef clause."); yyerrok; diff --git a/pform.cc b/pform.cc index f1602a589..7405a91c9 100644 --- a/pform.cc +++ b/pform.cc @@ -858,19 +858,40 @@ void pform_put_enum_type_in_scope(enum_type_t*enum_set) lexical_scope->enum_sets.push_back(enum_set); } -void pform_set_typedef(const struct vlltype&loc, perm_string name, - data_type_t*data_type, - std::list*unp_ranges) +static typedef_t *pform_get_typedef(const struct vlltype&loc, perm_string name) { - if(unp_ranges) - data_type = new uarray_type_t(data_type, unp_ranges); - typedef_t *&td = lexical_scope->typedefs[name]; if (!td) { td = new typedef_t(name); FILE_NAME(td, loc); add_local_symbol(lexical_scope, name, td); } + return td; +} + +void pform_forward_typedef(const struct vlltype&loc, perm_string name, + enum typedef_t::basic_type basic_type) +{ + typedef_t *td = pform_get_typedef(loc, name); + + if (!td->set_basic_type(basic_type)) { + cout << loc << " error: Incompatible basic type `" << basic_type + << "` for `" << name + << "`. Previously declared in this scope as `" + << td->get_basic_type() << "` at " << td->get_fileline() << "." + << endl; + error_count++; + } +} + +void pform_set_typedef(const struct vlltype&loc, perm_string name, + data_type_t*data_type, + std::list*unp_ranges) +{ + typedef_t *td = pform_get_typedef(loc, name); + + if(unp_ranges) + data_type = new uarray_type_t(data_type, unp_ranges); if (!td->set_data_type(data_type)) { cerr << loc << " error: Type identifier `" << name diff --git a/pform.h b/pform.h index 66c28900c..ed7577616 100644 --- a/pform.h +++ b/pform.h @@ -305,7 +305,9 @@ extern void pform_make_elab_task(const struct vlltype&li, extern void pform_set_typedef(const struct vlltype&loc, perm_string name, data_type_t*data_type, - std::list*unp_ranges); + std::list*unp_ranges = nullptr); +extern void pform_forward_typedef(const struct vlltype&loc, perm_string name, + enum typedef_t::basic_type basic_type); extern void pform_set_type_referenced(const struct vlltype&loc, const char*name); diff --git a/pform_types.cc b/pform_types.cc index 5f538b5e7..f69c5d908 100644 --- a/pform_types.cc +++ b/pform_types.cc @@ -54,3 +54,38 @@ bool typedef_t::set_data_type(data_type_t *t) return true; } + +bool typedef_t::set_basic_type(enum basic_type bt) +{ + if (bt == ANY) + return true; + if (basic_type != ANY && bt != basic_type) + return false; + + basic_type = bt; + + return true; +} + +std::ostream& operator<< (std::ostream&out, enum typedef_t::basic_type bt) +{ + switch (bt) { + case typedef_t::ANY: + out << "any"; + break; + case typedef_t::ENUM: + out << "enum"; + break; + case typedef_t::STRUCT: + out << "struct"; + break; + case typedef_t::UNION: + out << "union"; + break; + case typedef_t::CLASS: + out << "class"; + break; + } + + return out; +} diff --git a/pform_types.h b/pform_types.h index 509e1d5e2..1029e7225 100644 --- a/pform_types.h +++ b/pform_types.h @@ -174,14 +174,26 @@ class data_type_t : public PNamedItem { }; struct typedef_t : public PNamedItem { - explicit typedef_t(perm_string n) : name(n) { }; + explicit typedef_t(perm_string n) : basic_type(ANY), name(n) { }; ivl_type_t elaborate_type(Design*des, NetScope*scope); + enum basic_type { + ANY, + ENUM, + STRUCT, + UNION, + CLASS + }; + bool set_data_type(data_type_t *t); const data_type_t *get_data_type() const { return data_type.get(); } + bool set_basic_type(basic_type bt); + enum basic_type get_basic_type() const { return basic_type; } + protected: + enum basic_type basic_type; std::unique_ptr data_type; public: perm_string name; @@ -447,5 +459,6 @@ static inline std::ostream& operator<< (std::ostream&out, const data_type_t&that extern std::ostream& operator<< (std::ostream&out, const pform_name_t&); extern std::ostream& operator<< (std::ostream&out, const name_component_t&that); extern std::ostream& operator<< (std::ostream&out, const index_component_t&that); +extern std::ostream& operator<< (std::ostream&out, enum typedef_t::basic_type bt); #endif /* IVL_pform_types_H */ From 3787eca248f3bbcdeb68fb4c1651e03a66949011 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 15 Sep 2022 11:41:40 +0200 Subject: [PATCH 5/6] Add regression tests for forward typedefs Check that all sorts of forward typedefs are supported. Also check that any recursive use of a type results in an error. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_typedef_fwd_base.v | 47 ++++++++++++++++++++ ivtest/ivltests/sv_typedef_fwd_class.v | 46 +++++++++++++++++++ ivtest/ivltests/sv_typedef_fwd_enum1.v | 44 ++++++++++++++++++ ivtest/ivltests/sv_typedef_fwd_enum2.v | 23 ++++++++++ ivtest/ivltests/sv_typedef_fwd_enum3.v | 26 +++++++++++ ivtest/ivltests/sv_typedef_fwd_enum_fail.v | 14 ++++++ ivtest/ivltests/sv_typedef_fwd_struct.v | 39 ++++++++++++++++ ivtest/ivltests/sv_typedef_fwd_struct_fail.v | 18 ++++++++ ivtest/ivltests/sv_typedef_fwd_union.v | 41 +++++++++++++++++ ivtest/ivltests/sv_typedef_fwd_union_fail.v | 18 ++++++++ ivtest/regress-sv.list | 10 +++++ ivtest/regress-vlog95.list | 3 ++ 12 files changed, 329 insertions(+) create mode 100644 ivtest/ivltests/sv_typedef_fwd_base.v create mode 100644 ivtest/ivltests/sv_typedef_fwd_class.v create mode 100644 ivtest/ivltests/sv_typedef_fwd_enum1.v create mode 100644 ivtest/ivltests/sv_typedef_fwd_enum2.v create mode 100644 ivtest/ivltests/sv_typedef_fwd_enum3.v create mode 100644 ivtest/ivltests/sv_typedef_fwd_enum_fail.v create mode 100644 ivtest/ivltests/sv_typedef_fwd_struct.v create mode 100644 ivtest/ivltests/sv_typedef_fwd_struct_fail.v create mode 100644 ivtest/ivltests/sv_typedef_fwd_union.v create mode 100644 ivtest/ivltests/sv_typedef_fwd_union_fail.v diff --git a/ivtest/ivltests/sv_typedef_fwd_base.v b/ivtest/ivltests/sv_typedef_fwd_base.v new file mode 100644 index 000000000..46562aca9 --- /dev/null +++ b/ivtest/ivltests/sv_typedef_fwd_base.v @@ -0,0 +1,47 @@ +// Check that forward typedefs of basic types are supported + +`define check(val, exp) \ + if (val != exp) begin \ + $display("FAILED(%0d). '%s' expected ", `__LINE__, `"val`", exp, " got ", val, ); \ + failed = 1'b1; \ + end + +bit failed = 1'b0; + +module test; + typedef T1; + typedef T1; // Check forward typedef twice for the same type + typedef T2; + typedef T3; + typedef T4; + + T1 x = -1; + T2 y = 1.23; + T3 z = "Hello"; + T4 w; + + typedef integer T1; + // There can be as many forward typedefs as we like, even after the type + // itself has already been declared. + typedef T1; + typedef T1; + + typedef real T2; + typedef string T3; + typedef logic [1:0] T4[3:0]; + + initial begin + `check($bits(x), $bits(integer)) + `check($bits(T1), $bits(integer)) + `check(x, -1) + `check(y, 1.23) + `check(z, "Hello") + `check($unpacked_dimensions(w), 1) + `check($size(w), 4) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_typedef_fwd_class.v b/ivtest/ivltests/sv_typedef_fwd_class.v new file mode 100644 index 000000000..4a672f5c5 --- /dev/null +++ b/ivtest/ivltests/sv_typedef_fwd_class.v @@ -0,0 +1,46 @@ +// Check that forward typedefs of classes are supported + +module test; + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %d, got %d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + + bit failed = 1'b0; + + typedef class C; + typedef C; + + C x; + + class C; + int x; + endclass + + C y; + + // There can be as many forward typedefs as we like, even after the type + // itself has already been declared. + typedef C; + typedef class C; + + C z; + + initial begin + // Check they are all the same type and can be assigned to each other + x = y; + y = z; + z = x; + + `check($bits(x.x), $bits(int)); + `check($bits(y.x), $bits(int)); + `check($bits(z.x), $bits(int)); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_typedef_fwd_enum1.v b/ivtest/ivltests/sv_typedef_fwd_enum1.v new file mode 100644 index 000000000..6e3a90132 --- /dev/null +++ b/ivtest/ivltests/sv_typedef_fwd_enum1.v @@ -0,0 +1,44 @@ +// Check that forward enum typedefs are supported + +module test; + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + + bit failed = 1'b0; + + typedef T; + typedef enum T; + + T x; + + typedef enum integer { + A, B + } T; + + T y; + + typedef enum T; + typedef T; + + T z; + + initial begin + // Check that they are all the same type and can be assigned to each other + x = y; + y = z; + z = x; + + `check($bits(x), $bits(integer)) + `check($bits(y), $bits(integer)) + `check($bits(z), $bits(integer)) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_typedef_fwd_enum2.v b/ivtest/ivltests/sv_typedef_fwd_enum2.v new file mode 100644 index 000000000..d4fc02400 --- /dev/null +++ b/ivtest/ivltests/sv_typedef_fwd_enum2.v @@ -0,0 +1,23 @@ +// Check that the base type of an enum can be a forward typedef + +module test; + + typedef T1; + + typedef enum T1 { + A, B + } T2; + + typedef logic [31:0] T1; + + T2 z; + + initial begin + if ($bits(z) == 32) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_typedef_fwd_enum3.v b/ivtest/ivltests/sv_typedef_fwd_enum3.v new file mode 100644 index 000000000..3668d26ba --- /dev/null +++ b/ivtest/ivltests/sv_typedef_fwd_enum3.v @@ -0,0 +1,26 @@ +// Check that a forwarded enum typedef can be referenced in a class + +module test; + + typedef T; + + class C; + T x; + endclass + + typedef enum integer { + X, Y + } T; + + initial begin + C c; + c = new; + + if ($bits(c.x) == 32) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_typedef_fwd_enum_fail.v b/ivtest/ivltests/sv_typedef_fwd_enum_fail.v new file mode 100644 index 000000000..e05586e4e --- /dev/null +++ b/ivtest/ivltests/sv_typedef_fwd_enum_fail.v @@ -0,0 +1,14 @@ +// Check that a enum can't be its own base type + +module test; + + typedef T; + typedef enum T { + A, B + } T; + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_typedef_fwd_struct.v b/ivtest/ivltests/sv_typedef_fwd_struct.v new file mode 100644 index 000000000..f3593462b --- /dev/null +++ b/ivtest/ivltests/sv_typedef_fwd_struct.v @@ -0,0 +1,39 @@ +// Check that forward struct typedefs are supported + +module test; + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + + bit failed = 1'b0; + + typedef T; + typedef struct T; + + T x; + + typedef struct packed { + int x; + } T; + + T y; + + typedef struct T; + typedef T; + + T z; + + initial begin + `check($bits(x), $bits(int)) + `check($bits(y), $bits(int)) + `check($bits(z), $bits(int)) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_typedef_fwd_struct_fail.v b/ivtest/ivltests/sv_typedef_fwd_struct_fail.v new file mode 100644 index 000000000..eb680bd96 --- /dev/null +++ b/ivtest/ivltests/sv_typedef_fwd_struct_fail.v @@ -0,0 +1,18 @@ +// Check that it is an error to use a forwarded struct type as the type for the +// member in the struct itself. + +module test; + + typedef T; + + typedef struct packed { + T x; + } T; + + T x; + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_typedef_fwd_union.v b/ivtest/ivltests/sv_typedef_fwd_union.v new file mode 100644 index 000000000..9356d9065 --- /dev/null +++ b/ivtest/ivltests/sv_typedef_fwd_union.v @@ -0,0 +1,41 @@ +// Check that forward typdes of unions are supported + +module test; + +`define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end + + bit failed = 1'b0; + typedef union T; + typedef T; + + T x; + + typedef union packed { + int x; + logic [3:0][7:0] y; + } T; + + T y; + + // There can be as many forward typedefs as we like, even after the type + // itself has already been declared. + typedef T; + typedef union T; + + T z; + + initial begin + `check($bits(x), $bits(int)); + `check($bits(y), $bits(int)); + `check($bits(z), $bits(int)); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_typedef_fwd_union_fail.v b/ivtest/ivltests/sv_typedef_fwd_union_fail.v new file mode 100644 index 000000000..b77dc13da --- /dev/null +++ b/ivtest/ivltests/sv_typedef_fwd_union_fail.v @@ -0,0 +1,18 @@ +// Check that it is an error to use a forwarded union type as the type for the +// members in the union itself. + +module test; + + typedef T; + + typedef union packed { + T x; + } T; + + T x; + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index cf7a8f06a..7738d2119 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -720,6 +720,16 @@ sv_typedef_darray_base1 normal,-g2009 ivltests sv_typedef_darray_base2 normal,-g2009 ivltests sv_typedef_darray_base3 normal,-g2009 ivltests sv_typedef_darray_base4 normal,-g2009 ivltests +sv_typedef_fwd_base normal,-g2009 ivltests +sv_typedef_fwd_class normal,-g2009 ivltests +sv_typedef_fwd_union normal,-g2009 ivltests +sv_typedef_fwd_union_fail CE,-g2009 ivltests +sv_typedef_fwd_enum1 normal,-g2009 ivltests +sv_typedef_fwd_enum2 normal,-g2009 ivltests +sv_typedef_fwd_enum3 normal,-g2009 ivltests +sv_typedef_fwd_enum_fail CE,-g2009 ivltests +sv_typedef_fwd_struct normal,-g2009 ivltests +sv_typedef_fwd_struct_fail CE,-g2009 ivltests sv_typedef_nested_array normal,-g2009 ivltests sv_typedef_queue_base1 normal,-g2009 ivltests sv_typedef_queue_base2 normal,-g2009 ivltests diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index 30cbdc3e6..e520e2de3 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -302,6 +302,7 @@ sv_string5 CE,-g2009 ivltests sv_string6 CE,-g2009,-pallowsigned=1 ivltests sv_string7 CE,-g2009,-pallowsigned=1 ivltests sv_string7b CE,-g2009,-pallowsigned=1 ivltests +sv_typedef_fwd_base CE,-g2009 ivltests vhdl_string_lim CE,-g2005-sv,-pallowsigned=1,ivltests/vhdl_string_lim.vhd ivltests vhdl_textio_write CE,-g2005-sv,-pallowsigned=1,ivltests/vhdl_textio_write.vhd ivltests vhdl_textio_read CE,-g2005-sv,-pallowsigned=1,ivltests/vhdl_textio_read.vhd ivltests @@ -440,6 +441,8 @@ sv_port_default8 CE,-g2009,-pallowsigned=1 ivltests sv_port_default9 CE,-g2009 ivltests sv_ps_type_class1 CE,-g2009 ivltests sv_root_class CE,-g2009 ivltests +sv_typedef_fwd_class CE,-g2009 ivltests +sv_typedef_fwd_enum3 CE,-g2009 ivltests sv_typedef_scope3 CE,-g2009 ivltests sv_unit2b CE,-g2009 ivltests sv_unit3b CE,-g2009 ivltests From 10e35d15734fffb419a3cd19f8e0726bc58bbda1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Apr 2022 13:27:14 +0200 Subject: [PATCH 6/6] Add regression tests for circular type definitions Check that circular type definitions are detected and an error is reported. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/sv_typedef_circular1.v | 14 ++++++++++++++ ivtest/ivltests/sv_typedef_circular2.v | 18 ++++++++++++++++++ ivtest/regress-sv.list | 2 ++ 3 files changed, 34 insertions(+) create mode 100644 ivtest/ivltests/sv_typedef_circular1.v create mode 100644 ivtest/ivltests/sv_typedef_circular2.v diff --git a/ivtest/ivltests/sv_typedef_circular1.v b/ivtest/ivltests/sv_typedef_circular1.v new file mode 100644 index 000000000..998a21a50 --- /dev/null +++ b/ivtest/ivltests/sv_typedef_circular1.v @@ -0,0 +1,14 @@ +// Check that circular type definitions are detected and an error is reported. + +module test; + typedef T1; + typedef T1 T2; + typedef T2 T1; + + T2 x; + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_typedef_circular2.v b/ivtest/ivltests/sv_typedef_circular2.v new file mode 100644 index 000000000..638744e20 --- /dev/null +++ b/ivtest/ivltests/sv_typedef_circular2.v @@ -0,0 +1,18 @@ +// Check that longer chains of circular type definitions are detected as an +// error. + +module test; + + typedef T1; + + typedef struct packed { + T1 x; + } T2; + + typedef T2 [1:0] T3; + + typedef T3 T1; + + T1 x; + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index 7738d2119..f9456c777 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -716,6 +716,8 @@ sv_typedef_array_base2 normal,-g2009 ivltests sv_typedef_array_base3 normal,-g2009 ivltests sv_typedef_array_base4 normal,-g2009 ivltests sv_typedef_chained normal,-g2009 ivltests +sv_typedef_circular1 CE,-g2009 ivltests +sv_typedef_circular2 CE,-g2009 ivltests sv_typedef_darray_base1 normal,-g2009 ivltests sv_typedef_darray_base2 normal,-g2009 ivltests sv_typedef_darray_base3 normal,-g2009 ivltests