Implement the "local" class member protection.

Test during elaboration that the member really is
accessible in the context where the elaboration
happens.
This commit is contained in:
Stephen Williams 2013-06-26 09:16:24 -04:00
parent 046535cfbb
commit cf47a759d1
11 changed files with 169 additions and 77 deletions

View File

@ -1135,7 +1135,11 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
} }
const netclass_t* class_type = net->class_type(); 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_path = tmp_path;
use_darray = dynamic_cast<const netdarray_t*> (member_type); use_darray = dynamic_cast<const netdarray_t*> (member_type);
@ -1756,14 +1760,13 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
} }
static NetExpr* check_for_class_property(const LineInfo*li, static NetExpr* check_for_class_property(const LineInfo*li,
Design*des, NetScope*, Design*des, NetScope*scope,
NetNet*net, NetNet*net,
const name_component_t&comp) const name_component_t&comp)
{ {
const netclass_t*class_type = net->class_type(); const netclass_t*class_type = net->class_type();
const ivl_type_s*ptype = class_type->get_property(comp.name); int pidx = class_type->property_idx_from_name(comp.name);
if (pidx < 0) {
if (ptype == 0) {
cerr << li->get_fileline() << ": error: " cerr << li->get_fileline() << ": error: "
<< "Class " << class_type->get_name() << "Class " << class_type->get_name()
<< " has no property " << comp.name << "." << endl; << " has no property " << comp.name << "." << endl;
@ -1771,6 +1774,23 @@ static NetExpr* check_for_class_property(const LineInfo*li,
return 0; 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); NetEProperty*tmp = new NetEProperty(net, comp.name);
tmp->set_line(*li); tmp->set_line(*li);
return tmp; 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()) { if (const netclass_t*class_type = net->class_type()) {
const ivl_type_s*ptype = class_type->get_property(method_name); int pidx = class_type->property_idx_from_name(method_name);
if (ptype) { if (pidx >= 0) {
ivl_type_t ptype = class_type->get_prop_type(pidx);
expr_type_ = ptype->base_type(); expr_type_ = ptype->base_type();
expr_width_ = ptype->packed_width(); expr_width_ = ptype->packed_width();
min_width_ = expr_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 * not a method, or the name is not in the parent class, then
* fail. Otherwise, return a NetEProperty. * 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 unsigned, unsigned) const
{ {
if (!gn_system_verilog()) 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: " cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member: "
<< "Found member " << member_name << "Found member " << member_name
<< " is a member of class " << class_type->get_name() << " is a member of class " << class_type->get_name()
<< ", context scope=" << scope_path(scope)
<< ", so synthesizing a NetEProperty." << endl; << ", 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); NetEProperty*tmp = new NetEProperty(this_net, member_name);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;

View File

@ -316,7 +316,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
return lv; return lv;
} }
NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*, NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
NetScope*scope) const NetScope*scope) const
{ {
if (!gn_system_verilog()) if (!gn_system_verilog())
@ -812,7 +812,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
return true; 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, NetAssign_*lv,
const perm_string&method_name) const 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 /* Make sure the property is really present in the class. If
not, then generate an error message and return an error. */ not, then generate an error message and return an error. */
ivl_type_t ptype = class_type->get_property(method_name); int pidx = class_type->property_idx_from_name(method_name);
if (ptype == 0) { if (pidx < 0) {
cerr << get_fileline() << ": error: Class " << class_type->get_name() cerr << get_fileline() << ": error: Class " << class_type->get_name()
<< " does not have a property " << method_name << "." << endl; << " does not have a property " << method_name << "." << endl;
des->errors += 1; des->errors += 1;
return false; 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); lv->set_property(method_name);
ivl_type_t ptype = class_type->get_prop_type(pidx);
const netdarray_t*mtype = dynamic_cast<const netdarray_t*> (ptype); const netdarray_t*mtype = dynamic_cast<const netdarray_t*> (ptype);
if (mtype) { if (mtype) {
const name_component_t&name_tail = path_.back(); const name_component_t&name_tail = path_.back();

View File

@ -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 // Collect the properties, elaborate them, and add them to the
// elaborated class definition. // elaborated class definition.
for (map<perm_string, data_type_t*>::iterator cur = use_type->properties.begin() for (map<perm_string, class_type_t::prop_info_t>::iterator cur = use_type->properties.begin()
; cur != use_type->properties.end() ; ++ cur) { ; cur != use_type->properties.end() ; ++ cur) {
if (debug_scopes) { if (debug_scopes) {
cerr << pclass->get_fileline() << ": elaborate_scope_class: " cerr << pclass->get_fileline() << ": elaborate_scope_class: "
<< " Property " << cur->first << endl; << " 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); ivl_assert(*pclass, tmp);
use_class->set_property(cur->first, tmp); use_class->set_property(cur->first, cur->second.qual, tmp);
} }
for (map<perm_string,PTask*>::iterator cur = pclass->tasks.begin() for (map<perm_string,PTask*>::iterator cur = pclass->tasks.begin()

View File

@ -96,9 +96,9 @@ unsigned NetAssign_::lwidth() const
if (member_.nil()) if (member_.nil())
return 1; return 1;
const ivl_type_s*ptype = class_type->get_property(member_); int pidx = class_type->property_idx_from_name(member_);
ivl_assert(*sig_, ptype); ivl_assert(*sig_, pidx >= 0);
ivl_type_t ptype = class_type->get_prop_type(pidx);
return ptype->packed_width(); return ptype->packed_width();
} }
@ -118,7 +118,9 @@ ivl_variable_type_t NetAssign_::expr_type() const
if (member_.nil()) if (member_.nil())
return sig_->data_type(); 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(); return tmp->base_type();
} }
@ -138,8 +140,9 @@ const ivl_type_s* NetAssign_::net_type() const
if (member_.nil()) if (member_.nil())
return sig_->net_type(); return sig_->net_type();
const ivl_type_s*tmp = class_type->get_property(member_); int pidx = class_type->property_idx_from_name(member_);
ivl_assert(*sig_, tmp); ivl_assert(*sig_, pidx >= 0);
ivl_type_t tmp = class_type->get_prop_type(pidx);
return tmp; return tmp;
} }

View File

@ -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<perm_string,size_t>::const_iterator cur; map<perm_string,size_t>::const_iterator cur;
cur = properties_.find(pname); cur = properties_.find(pname);
@ -41,6 +41,7 @@ bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype)
prop_t tmp; prop_t tmp;
tmp.name = pname; tmp.name = pname;
tmp.qual = qual;
tmp.type = ptype; tmp.type = ptype;
property_table_.push_back(tmp); property_table_.push_back(tmp);
@ -59,17 +60,6 @@ ivl_variable_type_t netclass_t::base_type() const
return IVL_VT_CLASS; return IVL_VT_CLASS;
} }
const ivl_type_s* netclass_t::get_property(perm_string pname) const
{
map<perm_string,size_t>::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 int netclass_t::property_idx_from_name(perm_string pname) const
{ {
map<perm_string,size_t>::const_iterator cur; map<perm_string,size_t>::const_iterator cur;
@ -86,6 +76,12 @@ const char*netclass_t::get_prop_name(size_t idx) const
return property_table_[idx].name; 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 ivl_type_t netclass_t::get_prop_type(size_t idx) const
{ {
assert(idx < property_table_.size()); assert(idx < property_table_.size());
@ -99,3 +95,15 @@ NetScope*netclass_t::method_from_name(perm_string name) const
return task; 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;
}

View File

@ -22,6 +22,7 @@
# include "LineInfo.h" # include "LineInfo.h"
# include "ivl_target.h" # include "ivl_target.h"
# include "nettypes.h" # include "nettypes.h"
# include "property_qual.h"
# include <iostream> # include <iostream>
# include <map> # include <map>
@ -37,7 +38,7 @@ class netclass_t : public ivl_type_s {
// Set the property of the class during elaboration. Set the // Set the property of the class during elaboration. Set the
// name and type, and return true. If the name is already // name and type, and return true. If the name is already
// present, then return false. // 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 // Set the scope for the class. The scope has no parents and
// is used for the elaboration of methods (tasks/functions). // 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 // This is the name of the class type
inline perm_string get_name() const { return name_; } 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(); } inline size_t get_properties(void) const { return properties_.size(); }
// Get information about each property.
const char*get_prop_name(size_t idx) const; 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; 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; int property_idx_from_name(perm_string pname) const;
// The task method scopes from the method name. // The task method scopes from the method name.
NetScope*method_from_name(perm_string mname) const; 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_sig(Design*des, PClass*pclass);
void elaborate(Design*des, PClass*pclass); void elaborate(Design*des, PClass*pclass);
@ -75,6 +82,7 @@ class netclass_t : public ivl_type_s {
// Vector of properties. // Vector of properties.
struct prop_t { struct prop_t {
perm_string name; perm_string name;
property_qualifier_t qual;
ivl_type_s* type; ivl_type_s* type;
}; };
std::vector<prop_t> property_table_; std::vector<prop_t> property_table_;

12
parse.y
View File

@ -832,9 +832,9 @@ class_item /* IEEE1800-2005: A.1.8 */
; ;
class_item_qualifier /* IEEE1800-2005 A.1.8 */ class_item_qualifier /* IEEE1800-2005 A.1.8 */
: K_static { $$ = property_qualifier_t::set_static(); } : K_static { $$ = property_qualifier_t::make_static(); }
| K_protected { $$ = property_qualifier_t::set_protected(); } | K_protected { $$ = property_qualifier_t::make_protected(); }
| K_local { $$ = property_qualifier_t::set_local(); } | K_local { $$ = property_qualifier_t::make_local(); }
; ;
class_new /* IEEE1800-2005 A.2.4 */ 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_opt /* IEEE1800-2005 A.1.8: ... { property_qualifier } */
: property_qualifier_list { $$ = $1; } : property_qualifier_list { $$ = $1; }
| { $$ = property_qualifier_t::set_none(); } | { $$ = property_qualifier_t::make_none(); }
; ;
property_qualifier_list /* IEEE1800-2005 A.1.8 */ 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 */ random_qualifier /* IEEE1800-2005 A.1.8 */
: K_rand { $$ = property_qualifier_t::set_rand(); } : K_rand { $$ = property_qualifier_t::make_rand(); }
| K_randc { $$ = property_qualifier_t::set_randc(); } | K_randc { $$ = property_qualifier_t::make_randc(); }
; ;
/* real and realtime are exactly the same so save some code /* real and realtime are exactly the same so save some code

View File

@ -177,7 +177,7 @@ void class_type_t::pform_dump(ostream&out, unsigned indent) const
{ {
out << setw(indent) << "" << "class " << name << " {"; out << setw(indent) << "" << "class " << name << " {";
for (map<perm_string,data_type_t*>::const_iterator cur = properties.begin() for (map<perm_string,prop_info_t>::const_iterator cur = properties.begin()
; cur != properties.end() ; ++cur) { ; cur != properties.end() ; ++cur) {
out << " " << cur->first; out << " " << cur->first;
} }

View File

@ -64,7 +64,8 @@ void pform_class_property(const struct vlltype&loc,
use_type = new uarray_type_t(use_type, pd); 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()) { if (PExpr*rval = curp->expr.release()) {
PExpr*lval = new PEIdent(curp->name); PExpr*lval = new PEIdent(curp->name);

View File

@ -24,6 +24,7 @@
# include "LineInfo.h" # include "LineInfo.h"
# include "verinum.h" # include "verinum.h"
# include "named.h" # include "named.h"
# include "property_qual.h"
# include "ivl_target.h" # include "ivl_target.h"
# include <iostream> # include <iostream>
# include <list> # include <list>
@ -219,7 +220,13 @@ struct class_type_t : public data_type_t {
// This is the name of the class type. // This is the name of the class type.
perm_string name; perm_string name;
// This is a map of the properties. Map the name to the type. // This is a map of the properties. Map the name to the type.
std::map<perm_string, data_type_t*> 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<perm_string, struct prop_info_t> properties;
// This is an ordered list of property initializers. The name // This is an ordered list of property initializers. The name
// is the name of the property to be assigned, and the val is // 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; 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 * The pform_name_t is the general form for a hierarchical
* identifier. It is an ordered list of name components. Each name * identifier. It is an ordered list of name components. Each name

56
property_qual.h Normal file
View File

@ -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