diff --git a/elab_expr.cc b/elab_expr.cc index 7d5fbca09..68f19b24c 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1135,7 +1135,11 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope, } const netclass_t* class_type = net->class_type(); - member_type = class_type->get_property(member_name); + int midx = class_type->property_idx_from_name(member_name); + if (midx >= 0) + member_type = class_type->get_prop_type(midx); + else + member_type = 0; use_path = tmp_path; use_darray = dynamic_cast (member_type); @@ -1756,14 +1760,13 @@ static NetExpr* check_for_struct_members(const LineInfo*li, } static NetExpr* check_for_class_property(const LineInfo*li, - Design*des, NetScope*, + Design*des, NetScope*scope, NetNet*net, const name_component_t&comp) { const netclass_t*class_type = net->class_type(); - const ivl_type_s*ptype = class_type->get_property(comp.name); - - if (ptype == 0) { + int pidx = class_type->property_idx_from_name(comp.name); + if (pidx < 0) { cerr << li->get_fileline() << ": error: " << "Class " << class_type->get_name() << " has no property " << comp.name << "." << endl; @@ -1771,6 +1774,23 @@ static NetExpr* check_for_class_property(const LineInfo*li, return 0; } + if (debug_elaborate) { + cerr << li->get_fileline() << ": check_for_class_property: " + << "Property " << comp.name + << " of net " << net->name() + << ", context scope=" << scope_path(scope) + << endl; + } + + 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: " + << "Local property " << class_type->get_prop_name(pidx) + << " is not accessible in this context." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + } + NetEProperty*tmp = new NetEProperty(net, comp.name); tmp->set_line(*li); return tmp; @@ -2715,8 +2735,9 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) } if (const netclass_t*class_type = net->class_type()) { - const ivl_type_s*ptype = class_type->get_property(method_name); - if (ptype) { + int pidx = class_type->property_idx_from_name(method_name); + if (pidx >= 0) { + ivl_type_t ptype = class_type->get_prop_type(pidx); expr_type_ = ptype->base_type(); expr_width_ = ptype->packed_width(); min_width_ = expr_width_; @@ -2823,7 +2844,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, * not a method, or the name is not in the parent class, then * fail. Otherwise, return a NetEProperty. */ -NetExpr* PEIdent::elaborate_expr_class_member_(Design*, NetScope*scope, +NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, unsigned, unsigned) const { if (!gn_system_verilog()) @@ -2854,9 +2875,19 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*, NetScope*scope, cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member: " << "Found member " << member_name << " is a member of class " << class_type->get_name() + << ", context scope=" << scope_path(scope) << ", so synthesizing a NetEProperty." << endl; } + property_qualifier_t qual = class_type->get_prop_qual(pidx); + if (qual.test_local() && ! class_type->test_scope_is_method(scope)) { + cerr << get_fileline() << ": error: " + << "Local property " << class_type->get_prop_name(pidx) + << " is not accessible in this context." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + } + NetEProperty*tmp = new NetEProperty(this_net, member_name); tmp->set_line(*this); return tmp; diff --git a/elab_lval.cc b/elab_lval.cc index 7e1d5193a..86cecdcb0 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -316,7 +316,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, return lv; } -NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*, +NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, NetScope*scope) const { if (!gn_system_verilog()) @@ -812,7 +812,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, return true; } -bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*, +bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope, NetAssign_*lv, const perm_string&method_name) const { @@ -827,16 +827,26 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*, /* Make sure the property is really present in the class. If not, then generate an error message and return an error. */ - ivl_type_t ptype = class_type->get_property(method_name); - if (ptype == 0) { + int pidx = class_type->property_idx_from_name(method_name); + if (pidx < 0) { cerr << get_fileline() << ": error: Class " << class_type->get_name() << " does not have a property " << method_name << "." << endl; des->errors += 1; return false; } + property_qualifier_t qual = class_type->get_prop_qual(pidx); + if (qual.test_local() && ! class_type->test_scope_is_method(scope)) { + cerr << get_fileline() << ": error: " + << "Local property " << class_type->get_prop_name(pidx) + << " is not accessible (l-value) in this context." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + } + lv->set_property(method_name); + ivl_type_t ptype = class_type->get_prop_type(pidx); const netdarray_t*mtype = dynamic_cast (ptype); if (mtype) { const name_component_t&name_tail = path_.back(); diff --git a/elab_scope.cc b/elab_scope.cc index 7c9ddf3c3..7b0aa224a 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -366,15 +366,15 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) // Collect the properties, elaborate them, and add them to the // elaborated class definition. - for (map::iterator cur = use_type->properties.begin() + for (map::iterator cur = use_type->properties.begin() ; cur != use_type->properties.end() ; ++ cur) { if (debug_scopes) { cerr << pclass->get_fileline() << ": elaborate_scope_class: " << " Property " << cur->first << endl; } - ivl_type_s*tmp = cur->second->elaborate_type(des, scope); + ivl_type_s*tmp = cur->second.type->elaborate_type(des, scope); ivl_assert(*pclass, tmp); - use_class->set_property(cur->first, tmp); + use_class->set_property(cur->first, cur->second.qual, tmp); } for (map::iterator cur = pclass->tasks.begin() diff --git a/net_assign.cc b/net_assign.cc index d787478a8..0562fb1e5 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -96,9 +96,9 @@ unsigned NetAssign_::lwidth() const if (member_.nil()) return 1; - const ivl_type_s*ptype = class_type->get_property(member_); - ivl_assert(*sig_, ptype); - + int pidx = class_type->property_idx_from_name(member_); + ivl_assert(*sig_, pidx >= 0); + ivl_type_t ptype = class_type->get_prop_type(pidx); return ptype->packed_width(); } @@ -118,7 +118,9 @@ ivl_variable_type_t NetAssign_::expr_type() const if (member_.nil()) return sig_->data_type(); - const ivl_type_s*tmp = class_type->get_property(member_); + int pidx = class_type->property_idx_from_name(member_); + ivl_assert(*sig_, pidx >= 0); + ivl_type_t tmp = class_type->get_prop_type(pidx); return tmp->base_type(); } @@ -138,8 +140,9 @@ const ivl_type_s* NetAssign_::net_type() const if (member_.nil()) return sig_->net_type(); - const ivl_type_s*tmp = class_type->get_property(member_); - ivl_assert(*sig_, tmp); + int pidx = class_type->property_idx_from_name(member_); + ivl_assert(*sig_, pidx >= 0); + ivl_type_t tmp = class_type->get_prop_type(pidx); return tmp; } diff --git a/netclass.cc b/netclass.cc index 690443f13..91636b95d 100644 --- a/netclass.cc +++ b/netclass.cc @@ -32,7 +32,7 @@ netclass_t::~netclass_t() { } -bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype) +bool netclass_t::set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype) { map::const_iterator cur; cur = properties_.find(pname); @@ -41,6 +41,7 @@ bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype) prop_t tmp; tmp.name = pname; + tmp.qual = qual; tmp.type = ptype; property_table_.push_back(tmp); @@ -59,17 +60,6 @@ ivl_variable_type_t netclass_t::base_type() const return IVL_VT_CLASS; } -const ivl_type_s* netclass_t::get_property(perm_string pname) const -{ - map::const_iterator cur; - cur = properties_.find(pname); - if (cur == properties_.end()) - return 0; - - assert(property_table_.size() > cur->second); - return property_table_[cur->second].type; -} - int netclass_t::property_idx_from_name(perm_string pname) const { map::const_iterator cur; @@ -86,6 +76,12 @@ const char*netclass_t::get_prop_name(size_t idx) const return property_table_[idx].name; } +property_qualifier_t netclass_t::get_prop_qual(size_t idx) const +{ + assert(idx < property_table_.size()); + return property_table_[idx].qual; +} + ivl_type_t netclass_t::get_prop_type(size_t idx) const { assert(idx < property_table_.size()); @@ -99,3 +95,15 @@ NetScope*netclass_t::method_from_name(perm_string name) const return task; } + +bool netclass_t::test_scope_is_method(const NetScope*scope) const +{ + while (scope && scope != class_scope_) { + scope = scope->parent(); + } + + if (scope == 0) + return false; + else + return true; +} diff --git a/netclass.h b/netclass.h index 30bd1d087..8aac64583 100644 --- a/netclass.h +++ b/netclass.h @@ -22,6 +22,7 @@ # include "LineInfo.h" # include "ivl_target.h" # include "nettypes.h" +# include "property_qual.h" # include # include @@ -37,7 +38,7 @@ class netclass_t : public ivl_type_s { // Set the property of the class during elaboration. Set the // name and type, and return true. If the name is already // present, then return false. - bool set_property(perm_string pname, ivl_type_s*ptype); + bool set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype); // Set the scope for the class. The scope has no parents and // is used for the elaboration of methods (tasks/functions). @@ -50,17 +51,23 @@ class netclass_t : public ivl_type_s { // This is the name of the class type inline perm_string get_name() const { return name_; } - const ivl_type_s* get_property(perm_string pname) const; - inline size_t get_properties(void) const { return properties_.size(); } + // Get information about each property. const char*get_prop_name(size_t idx) const; + property_qualifier_t get_prop_qual(size_t idx) const; ivl_type_t get_prop_type(size_t idx) const; + // Map the name of a property to its index. int property_idx_from_name(perm_string pname) const; // The task method scopes from the method name. NetScope*method_from_name(perm_string mname) const; + // Test if this scope is a method within the class. This is + // used to check scope for handling data protection keywords + // "local" and "protected". + bool test_scope_is_method(const NetScope*scope) const; + void elaborate_sig(Design*des, PClass*pclass); void elaborate(Design*des, PClass*pclass); @@ -75,6 +82,7 @@ class netclass_t : public ivl_type_s { // Vector of properties. struct prop_t { perm_string name; + property_qualifier_t qual; ivl_type_s* type; }; std::vector property_table_; diff --git a/parse.y b/parse.y index f0bcbaa1b..bc120c050 100644 --- a/parse.y +++ b/parse.y @@ -832,9 +832,9 @@ class_item /* IEEE1800-2005: A.1.8 */ ; class_item_qualifier /* IEEE1800-2005 A.1.8 */ - : K_static { $$ = property_qualifier_t::set_static(); } - | K_protected { $$ = property_qualifier_t::set_protected(); } - | K_local { $$ = property_qualifier_t::set_local(); } + : K_static { $$ = property_qualifier_t::make_static(); } + | K_protected { $$ = property_qualifier_t::make_protected(); } + | K_local { $$ = property_qualifier_t::make_local(); } ; class_new /* IEEE1800-2005 A.2.4 */ @@ -1493,7 +1493,7 @@ property_qualifier /* IEEE1800-2005 A.1.8 */ property_qualifier_opt /* IEEE1800-2005 A.1.8: ... { property_qualifier } */ : property_qualifier_list { $$ = $1; } - | { $$ = property_qualifier_t::set_none(); } + | { $$ = property_qualifier_t::make_none(); } ; property_qualifier_list /* IEEE1800-2005 A.1.8 */ @@ -1502,8 +1502,8 @@ property_qualifier_list /* IEEE1800-2005 A.1.8 */ ; random_qualifier /* IEEE1800-2005 A.1.8 */ - : K_rand { $$ = property_qualifier_t::set_rand(); } - | K_randc { $$ = property_qualifier_t::set_randc(); } + : K_rand { $$ = property_qualifier_t::make_rand(); } + | K_randc { $$ = property_qualifier_t::make_randc(); } ; /* real and realtime are exactly the same so save some code diff --git a/pform_dump.cc b/pform_dump.cc index 2a1bd1e09..41251c679 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -177,7 +177,7 @@ void class_type_t::pform_dump(ostream&out, unsigned indent) const { out << setw(indent) << "" << "class " << name << " {"; - for (map::const_iterator cur = properties.begin() + for (map::const_iterator cur = properties.begin() ; cur != properties.end() ; ++cur) { out << " " << cur->first; } diff --git a/pform_pclass.cc b/pform_pclass.cc index c0ac9de55..05907aceb 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -64,7 +64,8 @@ void pform_class_property(const struct vlltype&loc, use_type = new uarray_type_t(use_type, pd); } - pform_cur_class->type->properties[curp->name] = use_type; + pform_cur_class->type->properties[curp->name] + = class_type_t::prop_info_t(property_qual,use_type); if (PExpr*rval = curp->expr.release()) { PExpr*lval = new PEIdent(curp->name); diff --git a/pform_types.h b/pform_types.h index b834884c3..bf657a474 100644 --- a/pform_types.h +++ b/pform_types.h @@ -24,6 +24,7 @@ # include "LineInfo.h" # include "verinum.h" # include "named.h" +# include "property_qual.h" # include "ivl_target.h" # include # include @@ -219,7 +220,13 @@ struct class_type_t : public data_type_t { // This is the name of the class type. perm_string name; // This is a map of the properties. Map the name to the type. - std::map properties; + struct prop_info_t { + inline prop_info_t() : qual(property_qualifier_t::make_none()), type(0) { } + inline prop_info_t(property_qualifier_t q, data_type_t*t) : qual(q), type(t) { } + property_qualifier_t qual; + data_type_t* type; + }; + std::map properties; // This is an ordered list of property initializers. The name // is the name of the property to be assigned, and the val is @@ -229,38 +236,6 @@ struct class_type_t : public data_type_t { ivl_type_s* elaborate_type(Design*, NetScope*) const; }; -class property_qualifier_t { - public: - static inline property_qualifier_t set_none() - { property_qualifier_t res; res.mask_ = 0; return res; } - - static inline property_qualifier_t set_static() - { property_qualifier_t res; res.mask_ = 1; return res; } - - static inline property_qualifier_t set_protected() - { property_qualifier_t res; res.mask_ = 2; return res; } - - static inline property_qualifier_t set_local() - { property_qualifier_t res; res.mask_ = 4; return res; } - - static inline property_qualifier_t set_rand() - { property_qualifier_t res; res.mask_ = 8; return res; } - - static inline property_qualifier_t set_randc() - { property_qualifier_t res; res.mask_ = 16; return res; } - - inline property_qualifier_t operator | (property_qualifier_t r) - { property_qualifier_t res; res.mask_ = mask_ | r.mask_; return res; } - - public: - inline bool test_static() const { return mask_ & 1; } - inline bool test_protected() const { return mask_ & 2; } - inline bool test_local() const { return mask_ & 4; } - - private: - int mask_; -}; - /* * The pform_name_t is the general form for a hierarchical * identifier. It is an ordered list of name components. Each name diff --git a/property_qual.h b/property_qual.h new file mode 100644 index 000000000..df02c7080 --- /dev/null +++ b/property_qual.h @@ -0,0 +1,56 @@ +#ifndef __property_qual_H +#define __property_qual_H +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +class property_qualifier_t { + public: + static inline property_qualifier_t make_none() + { property_qualifier_t res; res.mask_ = 0; return res; } + + static inline property_qualifier_t make_static() + { property_qualifier_t res; res.mask_ = 1; return res; } + + static inline property_qualifier_t make_protected() + { property_qualifier_t res; res.mask_ = 2; return res; } + + static inline property_qualifier_t make_local() + { property_qualifier_t res; res.mask_ = 4; return res; } + + static inline property_qualifier_t make_rand() + { property_qualifier_t res; res.mask_ = 8; return res; } + + static inline property_qualifier_t make_randc() + { property_qualifier_t res; res.mask_ = 16; return res; } + + inline property_qualifier_t operator | (property_qualifier_t r) + { property_qualifier_t res; res.mask_ = mask_ | r.mask_; return res; } + + public: + inline bool test_static() const { return mask_ & 1; } + inline bool test_protected() const { return mask_ & 2; } + inline bool test_local() const { return mask_ & 4; } + inline bool test_rand() const { return mask_ & 8; } + inline bool test_randc() const { return mask_ & 16; } + + private: + int mask_; +}; + +#endif