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 */