From 9e6f651e0963cc179be7f84313196b1039e4dfc1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 15 Jan 2022 13:08:32 +0100 Subject: [PATCH] Put enum type into scope when declaring it When creating an enum type it must be added to the scope where it is declared so it can later be elaborated and the enum and its names can be referenced in expressions. In addition the names of the enum must be added to the lexor scope so that name collisions are detected and can be reported as errors. This is done with pform_put_enum_type_in_scope() function. At the moment the function is called from two different places * When adding a typedef of a enum type * When creating a signal of a enum type In addition the enum_type_t is added to a class scope `enum_sets` when declaring a enum property in a class. But this only makes sure that the enum gets elaborated, its names are not added to the lexor scope. This works fine for the most part, but breaks for a few corner cases. E.g. it is possible to declare a enum type as part of the subtype of another packed type such as structs or packed arrays. E.g. ``` struct packed { enum { A } e; } s; ``` This is not covered by either of the cases above and neither do the names of the enum get added to the lexor scope, nor is the enum type elaborated. Another corner case that is currently not working is declaring a class property where the type is a typedef of a enum that is declared outside of the class. In this case the enum is elaborated again inside the class scope. E.g. the below is supposed to work, but fails with an already declared symbol error. ``` typedef enum { A } e_t; class C; typedef enum { A } e1; e_t e2; endclass ``` In addition since for enums declared in classes they are only added to `enum_sets`, but names are not added to the lexor scope, it is possible to declare a different symbol in the class scope with the same name. E.g. the following elaborates fine ``` class C; enum { A } e; typedef int A; endclass ``` To fix this call pform_put_enum_type_in_scope() when the enum_type_t is created in the parser. This makes sure that it is handled the same regardless where the type is declared or used. Signed-off-by: Lars-Peter Clausen --- parse.y | 1 + pform.cc | 9 +-------- pform.h | 2 ++ pform_pclass.cc | 4 ---- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/parse.y b/parse.y index 243f6703b..6c285e71f 100644 --- a/parse.y +++ b/parse.y @@ -2907,6 +2907,7 @@ enum_data_type /* IEEE 1800-2012 A.2.2.1 */ { enum_type_t*enum_type = $2; FILE_NAME(enum_type, @1); enum_type->names.reset($4); + pform_put_enum_type_in_scope(enum_type); $$ = enum_type; } ; diff --git a/pform.cc b/pform.cc index 98c49fb5e..1ee8de7d9 100644 --- a/pform.cc +++ b/pform.cc @@ -827,7 +827,7 @@ static void pform_put_wire_in_scope(perm_string name, PWire*net) lexical_scope->wires[name] = net; } -static void pform_put_enum_type_in_scope(enum_type_t*enum_set) +void pform_put_enum_type_in_scope(enum_type_t*enum_set) { if (lexical_scope->enum_sets.count(enum_set)) return; @@ -888,9 +888,6 @@ void pform_set_typedef(perm_string name, data_type_t*data_type, std::listname = name; - - if (enum_type_t*enum_type = dynamic_cast(data_type)) - pform_put_enum_type_in_scope(enum_type); } void pform_set_type_referenced(const struct vlltype&loc, const char*name) @@ -3592,10 +3589,6 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, // Add the file and line information to the enumeration type. FILE_NAME(&(enum_type->li), li); - // If this is an anonymous enumeration, attach it to the current scope. - if (enum_type->name.nil()) - pform_put_enum_type_in_scope(enum_type); - // Now apply the checked enumeration type to the variables // that are being declared with this type. for (list::iterator cur = names->begin() diff --git a/pform.h b/pform.h index a2d2d3f8d..e95e164ec 100644 --- a/pform.h +++ b/pform.h @@ -613,4 +613,6 @@ extern void pform_set_timeprec(const char*txt, bool initial_decl); extern bool allow_timeunit_decl; extern bool allow_timeprec_decl; +void pform_put_enum_type_in_scope(enum_type_t*enum_set); + #endif /* IVL_pform_H */ diff --git a/pform_pclass.cc b/pform_pclass.cc index 15c3d0e2a..e9facc013 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -69,10 +69,6 @@ void pform_class_property(const struct vlltype&loc, { assert(pform_cur_class); - if (enum_type_t*enum_set = dynamic_cast(data_type)) { - pform_cur_class->enum_sets .insert(enum_set); - } - // Add the non-static properties to the class type // object. Unwind the list of names to make a map of name to // type.