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 <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2022-01-15 13:08:32 +01:00
parent 74b433c083
commit 9e6f651e09
4 changed files with 4 additions and 12 deletions

View File

@ -2907,6 +2907,7 @@ enum_data_type /* IEEE 1800-2012 A.2.2.1 */
{ enum_type_t*enum_type = $2; { enum_type_t*enum_type = $2;
FILE_NAME(enum_type, @1); FILE_NAME(enum_type, @1);
enum_type->names.reset($4); enum_type->names.reset($4);
pform_put_enum_type_in_scope(enum_type);
$$ = enum_type; $$ = enum_type;
} }
; ;

View File

@ -827,7 +827,7 @@ static void pform_put_wire_in_scope(perm_string name, PWire*net)
lexical_scope->wires[name] = 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)) if (lexical_scope->enum_sets.count(enum_set))
return; return;
@ -888,9 +888,6 @@ void pform_set_typedef(perm_string name, data_type_t*data_type, std::list<pform_
ivl_assert(*data_type, ref == 0); ivl_assert(*data_type, ref == 0);
ref = data_type; ref = data_type;
ref->name = name; ref->name = name;
if (enum_type_t*enum_type = dynamic_cast<enum_type_t*>(data_type))
pform_put_enum_type_in_scope(enum_type);
} }
void pform_set_type_referenced(const struct vlltype&loc, const char*name) 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. // Add the file and line information to the enumeration type.
FILE_NAME(&(enum_type->li), li); 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 // Now apply the checked enumeration type to the variables
// that are being declared with this type. // that are being declared with this type.
for (list<perm_string>::iterator cur = names->begin() for (list<perm_string>::iterator cur = names->begin()

View File

@ -613,4 +613,6 @@ extern void pform_set_timeprec(const char*txt, bool initial_decl);
extern bool allow_timeunit_decl; extern bool allow_timeunit_decl;
extern bool allow_timeprec_decl; extern bool allow_timeprec_decl;
void pform_put_enum_type_in_scope(enum_type_t*enum_set);
#endif /* IVL_pform_H */ #endif /* IVL_pform_H */

View File

@ -69,10 +69,6 @@ void pform_class_property(const struct vlltype&loc,
{ {
assert(pform_cur_class); assert(pform_cur_class);
if (enum_type_t*enum_set = dynamic_cast<enum_type_t*>(data_type)) {
pform_cur_class->enum_sets .insert(enum_set);
}
// Add the non-static properties to the class type // Add the non-static properties to the class type
// object. Unwind the list of names to make a map of name to // object. Unwind the list of names to make a map of name to
// type. // type.