Support access to class constants on objects
It is allowed to access a constant declared in a class scope, such as a
enum value or parameter, on an object of that class type. This is described
in section 8.5 ("Object properties and object parameter data") of the LRM
(1800-2017).
E.g.
```
class C
enum { A } e;
endclass
C c = new;
c.e = c.A;
```
Support this by in addition of searching for class properties on the object
also search for constants in the class scope.
A bit of refactoring is needed around the parameter elaboration functions
since they expect a non-const NetScope, but for classes we only have a
const scope available.
The non-const scope is needed to be able to mark specparams as
non-annotatable. Since classes can't have specparams this part is factored
out into a separate function the NetScope parameter for the shared
functions is made const.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
ad23b08a10
commit
427091d3d3
24
PExpr.h
24
PExpr.h
|
|
@ -430,35 +430,42 @@ class PEIdent : public PExpr {
|
|||
NetAssign_*) const;
|
||||
|
||||
private:
|
||||
NetExpr*elaborate_expr_param_or_specparam_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
ivl_type_t par_type,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const;
|
||||
NetExpr*elaborate_expr_param_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetScope*found_in,
|
||||
ivl_type_t par_type,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const;
|
||||
NetExpr*elaborate_expr_param_bit_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetScope*found_in,
|
||||
ivl_type_t par_type,
|
||||
bool need_const) const;
|
||||
NetExpr*elaborate_expr_param_part_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetScope*found_in,
|
||||
ivl_type_t par_type,
|
||||
unsigned expr_wid) const;
|
||||
NetExpr*elaborate_expr_param_idx_up_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetScope*found_in,
|
||||
ivl_type_t par_type,
|
||||
bool need_const) const;
|
||||
NetExpr*elaborate_expr_param_idx_do_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetScope*found_in,
|
||||
ivl_type_t par_type,
|
||||
bool need_const) const;
|
||||
NetExpr*elaborate_expr_net(Design*des,
|
||||
|
|
@ -504,8 +511,15 @@ class PEIdent : public PExpr {
|
|||
unsigned expr_wid,
|
||||
unsigned flags) const;
|
||||
|
||||
NetExpr *elaborate_expr_class_field_(Design*des, NetScope*scope,
|
||||
NetNet*net,
|
||||
const name_component_t&comp,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const;
|
||||
|
||||
unsigned test_width_method_(Design*des, NetScope*scope, width_mode_t&mode);
|
||||
|
||||
unsigned test_width_parameter_(const NetExpr *par, width_mode_t&mode);
|
||||
|
||||
private:
|
||||
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
|
|
|
|||
145
elab_expr.cc
145
elab_expr.cc
|
|
@ -2516,15 +2516,24 @@ static NetExpr* class_static_property_expression(const LineInfo*li,
|
|||
return expr;
|
||||
}
|
||||
|
||||
static NetExpr* check_for_class_property(const LineInfo*li,
|
||||
Design*des, NetScope*scope,
|
||||
NetNet*net,
|
||||
const name_component_t&comp)
|
||||
NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope,
|
||||
NetNet*net,
|
||||
const name_component_t&comp,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const
|
||||
{
|
||||
const netclass_t*class_type = net->class_type();
|
||||
|
||||
ivl_type_t par_type;
|
||||
const NetExpr *par_val = class_type->get_parameter(des, comp.name, par_type);
|
||||
if (par_val)
|
||||
return elaborate_expr_param_(des, scope, par_val,
|
||||
class_type->class_scope(), par_type,
|
||||
expr_wid, flags);
|
||||
|
||||
int pidx = class_type->property_idx_from_name(comp.name);
|
||||
if (pidx < 0) {
|
||||
cerr << li->get_fileline() << ": error: "
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Class " << class_type->get_name()
|
||||
<< " has no property " << comp.name << "." << endl;
|
||||
des->errors += 1;
|
||||
|
|
@ -2532,7 +2541,7 @@ static NetExpr* check_for_class_property(const LineInfo*li,
|
|||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << li->get_fileline() << ": check_for_class_property: "
|
||||
cerr << get_fileline() << ": check_for_class_property: "
|
||||
<< "Property " << comp.name
|
||||
<< " of net " << net->name()
|
||||
<< ", context scope=" << scope_path(scope)
|
||||
|
|
@ -2541,7 +2550,7 @@ static NetExpr* check_for_class_property(const LineInfo*li,
|
|||
|
||||
property_qualifier_t qual = class_type->get_prop_qual(pidx);
|
||||
if (qual.test_local() && ! class_type->test_scope_is_method(scope)) {
|
||||
cerr << li->get_fileline() << ": error: "
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Local property " << class_type->get_prop_name(pidx)
|
||||
<< " is not accessible in this context."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
|
|
@ -2550,12 +2559,12 @@ static NetExpr* check_for_class_property(const LineInfo*li,
|
|||
|
||||
if (qual.test_static()) {
|
||||
perm_string prop_name = lex_strings.make(class_type->get_prop_name(pidx));
|
||||
return class_static_property_expression(li, class_type,
|
||||
return class_static_property_expression(this, class_type,
|
||||
prop_name);
|
||||
}
|
||||
|
||||
NetEProperty*tmp = new NetEProperty(net, comp.name);
|
||||
tmp->set_line(*li);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
@ -3977,6 +3986,33 @@ unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&)
|
|||
return 0;
|
||||
}
|
||||
|
||||
unsigned PEIdent::test_width_parameter_(const NetExpr *par, width_mode_t&mode)
|
||||
{
|
||||
// The width of an enumeration literal is the width of the
|
||||
// enumeration base.
|
||||
if (const NetEConstEnum*par_enum = dynamic_cast<const NetEConstEnum*> (par)) {
|
||||
const netenum_t*use_enum = par_enum->enumeration();
|
||||
ivl_assert(*this, use_enum != 0);
|
||||
|
||||
expr_type_ = use_enum->base_type();
|
||||
expr_width_ = use_enum->packed_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = par_enum->has_sign();
|
||||
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
expr_type_ = par->expr_type();
|
||||
expr_width_ = par->expr_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = par->has_sign();
|
||||
|
||||
if (!par->has_width() && (mode < LOSSLESS))
|
||||
mode = LOSSLESS;
|
||||
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||
{
|
||||
NetScope*use_scope = scope;
|
||||
|
|
@ -4128,6 +4164,11 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
if (sr.net->class_type() != 0 && !sr.path_tail.empty()) {
|
||||
const netclass_t*class_type = sr.net->class_type();
|
||||
perm_string pname = peek_tail_name(sr.path_tail);
|
||||
ivl_type_t par_type;
|
||||
const NetExpr *par = class_type->get_parameter(des, pname, par_type);
|
||||
if (par)
|
||||
return test_width_parameter_(par, mode);
|
||||
|
||||
int pidx = class_type->property_idx_from_name(pname);
|
||||
if (pidx >= 0) {
|
||||
ivl_type_t ptype = class_type->get_prop_type(pidx);
|
||||
|
|
@ -4172,33 +4213,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
|||
return expr_width_;
|
||||
}
|
||||
|
||||
// The width of an enumeration literal is the width of the
|
||||
// enumeration base.
|
||||
if (const NetEConstEnum*par_enum = dynamic_cast<const NetEConstEnum*> (sr.par_val)) {
|
||||
const netenum_t*use_enum = par_enum->enumeration();
|
||||
ivl_assert(*this, use_enum != 0);
|
||||
|
||||
expr_type_ = use_enum->base_type();
|
||||
expr_width_ = use_enum->packed_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = par_enum->has_sign();
|
||||
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
// The width of a parameter is the width of the parameter value
|
||||
// (as evaluated earlier).
|
||||
if (sr.par_val != 0) {
|
||||
expr_type_ = sr.par_val->expr_type();
|
||||
expr_width_ = sr.par_val->expr_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = sr.par_val->has_sign();
|
||||
|
||||
if (!sr.par_val->has_width() && (mode < LOSSLESS))
|
||||
mode = LOSSLESS;
|
||||
|
||||
return expr_width_;
|
||||
}
|
||||
if (sr.par_val != 0)
|
||||
return test_width_parameter_(sr.par_val, mode);
|
||||
|
||||
if (path_.size() == 1
|
||||
&& scope->genvar_tmp.str()
|
||||
|
|
@ -4283,8 +4301,8 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
<< " look for property " << member_comp << endl;
|
||||
}
|
||||
|
||||
return check_for_class_property(this, des, scope,
|
||||
net, member_comp);
|
||||
return elaborate_expr_class_field_(des, scope, net,
|
||||
member_comp, 0, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4578,8 +4596,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
des->errors += 1;
|
||||
}
|
||||
|
||||
NetExpr*tmp = elaborate_expr_param_(des, scope, sr.par_val, sr.scope,
|
||||
sr.par_type, expr_wid, flags);
|
||||
NetExpr*tmp = elaborate_expr_param_or_specparam_(des, scope, sr.par_val,
|
||||
sr.scope, sr.par_type,
|
||||
expr_wid, flags);
|
||||
|
||||
if (!tmp) return 0;
|
||||
|
||||
|
|
@ -4808,8 +4827,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
|
||||
ivl_assert(*this, sr.path_tail.size() == 1);
|
||||
const name_component_t member_comp = sr.path_tail.front();
|
||||
return check_for_class_property(this, des, use_scope,
|
||||
sr.net, member_comp);
|
||||
return elaborate_expr_class_field_(des, use_scope,
|
||||
sr.net, member_comp,
|
||||
expr_wid, flags);
|
||||
}
|
||||
|
||||
if (sr.net->enumeration() && !sr.path_tail.empty()) {
|
||||
|
|
@ -5007,7 +5027,7 @@ static verinum param_part_select_bits(const verinum&par_val, long wid,
|
|||
|
||||
NetExpr* PEIdent::elaborate_expr_param_bit_(Design*des, NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetScope*found_in,
|
||||
ivl_type_t par_type,
|
||||
bool need_const) const
|
||||
{
|
||||
|
|
@ -5100,7 +5120,7 @@ NetExpr* PEIdent::elaborate_expr_param_bit_(Design*des, NetScope*scope,
|
|||
|
||||
NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*,
|
||||
const NetScope*,
|
||||
ivl_type_t par_type,
|
||||
unsigned expr_wid) const
|
||||
{
|
||||
|
|
@ -5226,7 +5246,7 @@ static void warn_param_ob(long par_msv, long par_lsv, bool defined,
|
|||
|
||||
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetScope*found_in,
|
||||
ivl_type_t par_type,
|
||||
bool need_const) const
|
||||
{
|
||||
|
|
@ -5306,7 +5326,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
|
|||
|
||||
NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetScope*found_in,
|
||||
ivl_type_t par_type,
|
||||
bool need_const) const
|
||||
{
|
||||
|
|
@ -5385,6 +5405,31 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
|
|||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_param_or_specparam_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
ivl_type_t par_type,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const
|
||||
{
|
||||
bool need_const = NEED_CONST & flags;
|
||||
|
||||
if (need_const && !(ANNOTATABLE & flags)) {
|
||||
perm_string name = peek_tail_name(path_);
|
||||
if (found_in->make_parameter_unannotatable(name)) {
|
||||
cerr << get_fileline() << ": warning: specparam '" << name
|
||||
<< "' is being used in a constant expression." << endl;
|
||||
cerr << get_fileline() << ": : This will prevent it "
|
||||
"being annotated at run time." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return elaborate_expr_param_(des, scope, par, found_in, par_type,
|
||||
expr_wid, flags);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handle the case that the identifier is a parameter reference. The
|
||||
* parameter expression has already been located for us (as the par
|
||||
|
|
@ -5393,7 +5438,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope,
|
|||
NetExpr* PEIdent::elaborate_expr_param_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetScope*found_in,
|
||||
ivl_type_t par_type,
|
||||
unsigned expr_wid, unsigned flags) const
|
||||
{
|
||||
|
|
@ -5410,16 +5455,6 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
|
|||
<< "par_type: <nil>" << endl;
|
||||
}
|
||||
|
||||
if (need_const && !(ANNOTATABLE & flags)) {
|
||||
perm_string name = peek_tail_name(path_);
|
||||
if (found_in->make_parameter_unannotatable(name)) {
|
||||
cerr << get_fileline() << ": warning: specparam '" << name
|
||||
<< "' is being used in a constant expression." << endl;
|
||||
cerr << get_fileline() << ": : This will prevent it "
|
||||
"being annotated at run time." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
const name_component_t&name_tail = path_.back();
|
||||
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
||||
if (!name_tail.index.empty())
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ initial begin
|
|||
|
||||
// Not yet supported
|
||||
// c.e2 = C::A;
|
||||
// c.e2 = c.A;
|
||||
c.e2 = c.A;
|
||||
|
||||
// Check that they have the numerical value from the right scope
|
||||
if (c.e1 == 1 && c.e2 == 10) begin
|
||||
|
|
|
|||
|
|
@ -188,3 +188,9 @@ bool netclass_t::test_scope_is_method(const NetScope*scope) const
|
|||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
const NetExpr* netclass_t::get_parameter(Design *des, perm_string name,
|
||||
ivl_type_t &par_type) const
|
||||
{
|
||||
return class_scope_->get_parameter(des, name, par_type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
# include <map>
|
||||
|
||||
class Design;
|
||||
class NetExpr;
|
||||
class NetNet;
|
||||
class NetScope;
|
||||
class PClass;
|
||||
|
|
@ -112,6 +113,9 @@ class netclass_t : public ivl_type_s {
|
|||
std::ostream& debug_dump(std::ostream&fd) const;
|
||||
void dump_scope(std::ostream&fd) const;
|
||||
|
||||
const NetExpr* get_parameter(Design *des, perm_string name,
|
||||
ivl_type_t &par_type) const;
|
||||
|
||||
private:
|
||||
perm_string name_;
|
||||
// If this is derived from another base class, point to it
|
||||
|
|
|
|||
Loading…
Reference in New Issue