diff --git a/elab_scope.cc b/elab_scope.cc index 826154eae..99a14081d 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -496,29 +496,30 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) << endl; } - class_type_t*base_class = dynamic_cast (use_type->base_type); - if (use_type->base_type && !base_class) { - cerr << pclass->get_fileline() << ": error: " - << "Base type of " << use_type->name - << " is not a class." << endl; - des->errors += 1; - } - netclass_t*use_base_class = 0; - if (base_class) { - use_base_class = base_class->save_elaborated_type; - if (use_base_class == 0) { + const netclass_t*use_base_class = 0; + if (use_type->base_type) { + ivl_type_t base_type = use_type->base_type->elaborate_type(des, scope); + use_base_class = dynamic_cast(base_type); + if (!use_base_class) { cerr << pclass->get_fileline() << ": error: " - << "Base class " << base_class->name - << " not found." << endl; + << "Base type of " << use_type->name + << " is not a class." << endl; des->errors += 1; } } netclass_t*use_class = new netclass_t(use_type->name, use_base_class); - ivl_assert(*pclass, use_type->save_elaborated_type == 0); - use_type->save_elaborated_type = use_class; + // If this is a package we need to remember the elaborated type so that + // scoped type references work. Since there is only one instance for each + // package this works. For classes defined in modules there might be + // multiple instances though. Each module instance will have its own class + // type instance, so the same does not work there. + if (scope->type() == NetScope::PACKAGE) { + ivl_assert(*pclass, use_type->save_elaborated_type == 0); + use_type->save_elaborated_type = use_class; + } NetScope*class_scope = new NetScope(scope, hname_t(pclass->pscope_name()), NetScope::CLASS, scope->unit()); diff --git a/elab_type.cc b/elab_type.cc index 948836856..ecd81e098 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -101,10 +101,11 @@ ivl_type_t atom2_type_t::elaborate_type_raw(Design*des, NetScope*) const } } -ivl_type_t class_type_t::elaborate_type_raw(Design*, NetScope*) const +ivl_type_t class_type_t::elaborate_type_raw(Design*des, NetScope*scope) const { - ivl_assert(*this, save_elaborated_type); - return save_elaborated_type; + if (save_elaborated_type) + return save_elaborated_type; + return scope->find_class(des, name); } /* diff --git a/ivtest/ivltests/sv_class_in_module_decl.v b/ivtest/ivltests/sv_class_in_module_decl.v new file mode 100644 index 000000000..267bed7b9 --- /dev/null +++ b/ivtest/ivltests/sv_class_in_module_decl.v @@ -0,0 +1,32 @@ +// Check that it is possible to have multiple instances of a module that defines +// a class and that the actual class types can have different implementations +// based on module parameters. + +module M #( + parameter X = 0 +); + + class C; + function int f; + return X; + endfunction + endclass + + C c = new; + +endmodule + +module test; + + M #(10) m1(); + M #(20) m2(); + + initial begin + if (m1.c.f() == 10 && m2.c.f() == 20) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index 291377749..43fb411a0 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -478,6 +478,7 @@ sv_class_empty_item normal,-g2009 ivltests sv_class_extends_scoped normal,-g2009 ivltests sv_class_localparam normal,-g2009 ivltests sv_class_new_init normal,-g2009 ivltests +sv_class_in_module_decl normal,-g2009 ivltests sv_darray1 normal,-g2009 ivltests sv_darray2 normal,-g2009 ivltests sv_darray3 normal,-g2009 ivltests diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index 8357e0afc..d4b6a7303 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -376,6 +376,7 @@ sv_class_empty_item CE,-g2009 ivltests sv_class_extends_scoped CE,-g2009 ivltests sv_class_localparam CE,-g2009 ivltests sv_class_new_init CE,-g2009 ivltests +sv_class_in_module_decl CE,-g2009 ivltests sv_end_label CE,-g2009 ivltests # Also generate sv_foreach2 CE,-g2009,-pallowsigned=1 ivltests sv_foreach3 CE,-g2009 ivltests diff --git a/netclass.cc b/netclass.cc index 82be2c55e..3365a8949 100644 --- a/netclass.cc +++ b/netclass.cc @@ -23,8 +23,8 @@ using namespace std; -netclass_t::netclass_t(perm_string name, netclass_t*sup) -: name_(name), super_(sup), class_scope_(0), definition_scope_(0) +netclass_t::netclass_t(perm_string name, const netclass_t*super) +: name_(name), super_(super), class_scope_(0), definition_scope_(0) { } diff --git a/netclass.h b/netclass.h index 7274bd5f7..af473ba71 100644 --- a/netclass.h +++ b/netclass.h @@ -35,7 +35,7 @@ class PExpr; class netclass_t : public ivl_type_s { public: - netclass_t(perm_string class_name, netclass_t*par); + netclass_t(perm_string class_name, const netclass_t*super); ~netclass_t(); // Set the property of the class during elaboration. Set the @@ -120,7 +120,7 @@ class netclass_t : public ivl_type_s { perm_string name_; // If this is derived from another base class, point to it // here. - netclass_t*super_; + const netclass_t*super_; // Map property names to property table index. std::map properties_; // Vector of properties.