mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Fix parameter attributes pretending to be records
Parameters relied on is_record for a couple of validations, but they are not records and should not be treated as such. This way we can validate &optional better.
This commit is contained in:
parent
4e5a56c5e0
commit
4445bc1daf
5 changed files with 22 additions and 18 deletions
18
src/Attr.cc
18
src/Attr.cc
|
@ -166,13 +166,9 @@ detail::TraversalCode Attr::Traverse(detail::TraversalCallback* cb) const {
|
||||||
HANDLE_TC_ATTR_POST(tc);
|
HANDLE_TC_ATTR_POST(tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
Attributes::Attributes(TypePtr t, bool arg_in_record, bool is_global)
|
Attributes::Attributes(std::vector<AttrPtr> a, TypePtr t, bool in_record, bool is_global, bool is_param)
|
||||||
: Attributes(std::vector<AttrPtr>{}, std::move(t), arg_in_record, is_global) {}
|
: type(std::move(t)), in_record(in_record), global_var(is_global), is_param(is_param) {
|
||||||
|
|
||||||
Attributes::Attributes(std::vector<AttrPtr> a, TypePtr t, bool arg_in_record, bool is_global) : type(std::move(t)) {
|
|
||||||
attrs.reserve(a.size());
|
attrs.reserve(a.size());
|
||||||
in_record = arg_in_record;
|
|
||||||
global_var = is_global;
|
|
||||||
|
|
||||||
SetLocationInfo(&start_location, &end_location);
|
SetLocationInfo(&start_location, &end_location);
|
||||||
|
|
||||||
|
@ -331,7 +327,7 @@ bool Attributes::CheckAttr(Attr* a) {
|
||||||
return AttrError("&default and &default_insert cannot be used together");
|
return AttrError("&default and &default_insert cannot be used together");
|
||||||
|
|
||||||
std::string err_msg;
|
std::string err_msg;
|
||||||
if ( ! check_default_attr(a, type, global_var, in_record, err_msg) && ! err_msg.empty() )
|
if ( ! check_default_attr(a, type, global_var, in_record || is_param, err_msg) && ! err_msg.empty() )
|
||||||
return AttrError(err_msg.c_str());
|
return AttrError(err_msg.c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -344,7 +340,7 @@ bool Attributes::CheckAttr(Attr* a) {
|
||||||
return AttrError("Using &default and &optional together results in &default behavior");
|
return AttrError("Using &default and &optional together results in &default behavior");
|
||||||
|
|
||||||
std::string err_msg;
|
std::string err_msg;
|
||||||
if ( ! check_default_attr(a, type, global_var, in_record, err_msg) && ! err_msg.empty() )
|
if ( ! check_default_attr(a, type, global_var, in_record || is_param, err_msg) && ! err_msg.empty() )
|
||||||
return AttrError(err_msg.c_str());
|
return AttrError(err_msg.c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -586,7 +582,7 @@ bool Attributes::operator==(const Attributes& other) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_default_attr(Attr* a, const TypePtr& type, bool global_var, bool in_record, std::string& err_msg) {
|
bool check_default_attr(Attr* a, const TypePtr& type, bool global_var, bool record_like, std::string& err_msg) {
|
||||||
ASSERT(a->Tag() == ATTR_DEFAULT || a->Tag() == ATTR_DEFAULT_INSERT);
|
ASSERT(a->Tag() == ATTR_DEFAULT || a->Tag() == ATTR_DEFAULT_INSERT);
|
||||||
std::string aname = attr_name(a->Tag());
|
std::string aname = attr_name(a->Tag());
|
||||||
// &default is allowed for global tables, since it's used in
|
// &default is allowed for global tables, since it's used in
|
||||||
|
@ -598,7 +594,7 @@ bool check_default_attr(Attr* a, const TypePtr& type, bool global_var, bool in_r
|
||||||
|
|
||||||
const auto& atype = a->GetExpr()->GetType();
|
const auto& atype = a->GetExpr()->GetType();
|
||||||
|
|
||||||
if ( type->Tag() != TYPE_TABLE || (type->IsSet() && ! in_record) ) {
|
if ( type->Tag() != TYPE_TABLE || (type->IsSet() && ! record_like) ) {
|
||||||
if ( same_type(atype, type) )
|
if ( same_type(atype, type) )
|
||||||
// Ok.
|
// Ok.
|
||||||
return true;
|
return true;
|
||||||
|
@ -628,7 +624,7 @@ bool check_default_attr(Attr* a, const TypePtr& type, bool global_var, bool in_r
|
||||||
TableType* tt = type->AsTableType();
|
TableType* tt = type->AsTableType();
|
||||||
const auto& ytype = tt->Yield();
|
const auto& ytype = tt->Yield();
|
||||||
|
|
||||||
if ( ! in_record ) { // &default applies to the type itself.
|
if ( ! record_like ) { // &default applies to the type itself.
|
||||||
if ( same_type(atype, ytype) )
|
if ( same_type(atype, ytype) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
11
src/Attr.h
11
src/Attr.h
|
@ -108,8 +108,14 @@ protected:
|
||||||
// Manages a collection of attributes.
|
// Manages a collection of attributes.
|
||||||
class Attributes final : public Obj {
|
class Attributes final : public Obj {
|
||||||
public:
|
public:
|
||||||
Attributes(std::vector<AttrPtr> a, TypePtr t, bool in_record, bool is_global);
|
Attributes(std::vector<AttrPtr> a, TypePtr t, bool in_record, bool is_global, bool is_param);
|
||||||
Attributes(TypePtr t, bool in_record, bool is_global);
|
|
||||||
|
Attributes(TypePtr t, bool in_record, bool is_global)
|
||||||
|
: Attributes(std::vector<AttrPtr>{}, std::move(t), in_record, is_global, false) {}
|
||||||
|
|
||||||
|
Attributes(std::vector<AttrPtr> a, TypePtr t, bool in_record, bool is_global)
|
||||||
|
: Attributes(a, std::move(t), in_record, is_global, false) {}
|
||||||
|
|
||||||
|
|
||||||
~Attributes() override = default;
|
~Attributes() override = default;
|
||||||
|
|
||||||
|
@ -142,6 +148,7 @@ protected:
|
||||||
|
|
||||||
bool in_record;
|
bool in_record;
|
||||||
bool global_var;
|
bool global_var;
|
||||||
|
bool is_param;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Checks whether default attribute "a" is compatible with the given type.
|
// Checks whether default attribute "a" is compatible with the given type.
|
||||||
|
|
|
@ -257,11 +257,11 @@ static void extend_record(ID* id, std::unique_ptr<type_decl_list> fields, std::u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static AttributesPtr make_attributes(std::vector<AttrPtr>* attrs, TypePtr t, bool in_record, bool is_global) {
|
static AttributesPtr make_attributes(std::vector<AttrPtr>* attrs, TypePtr t, bool in_record, bool is_param) {
|
||||||
if ( ! attrs )
|
if ( ! attrs )
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto rval = make_intrusive<Attributes>(std::move(*attrs), std::move(t), in_record, is_global);
|
auto rval = make_intrusive<Attributes>(std::move(*attrs), std::move(t), in_record, /*is_global=*/false, is_param);
|
||||||
delete attrs;
|
delete attrs;
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
@ -1296,7 +1296,7 @@ type_decl:
|
||||||
TOK_ID ':' type opt_attr ';'
|
TOK_ID ':' type opt_attr ';'
|
||||||
{
|
{
|
||||||
set_location(@1, @4);
|
set_location(@1, @4);
|
||||||
auto attrs = make_attributes($4, {NewRef{}, $3}, in_record > 0, false);
|
auto attrs = make_attributes($4, {NewRef{}, $3}, in_record > 0, /*is_param=*/false);
|
||||||
$$ = new TypeDecl($1, {AdoptRef{}, $3}, std::move(attrs));
|
$$ = new TypeDecl($1, {AdoptRef{}, $3}, std::move(attrs));
|
||||||
|
|
||||||
if ( in_record > 0 && cur_decl_type_id )
|
if ( in_record > 0 && cur_decl_type_id )
|
||||||
|
@ -1327,7 +1327,7 @@ formal_args_decl:
|
||||||
TOK_ID ':' type opt_attr
|
TOK_ID ':' type opt_attr
|
||||||
{
|
{
|
||||||
set_location(@1, @4);
|
set_location(@1, @4);
|
||||||
auto attrs = make_attributes($4, {NewRef{}, $3}, true, false);
|
auto attrs = make_attributes($4, {NewRef{}, $3}, /*in_record=*/false, /*is_param=*/true);
|
||||||
$$ = new TypeDecl($1, {AdoptRef{}, $3}, std::move(attrs));
|
$$ = new TypeDecl($1, {AdoptRef{}, $3}, std::move(attrs));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
error in <...>/invalid-optional-attr.zeek, line 5: &optional is only valid for record fields (&optional)
|
error in <...>/invalid-optional-attr.zeek, line 5: &optional is only valid for record fields (&optional)
|
||||||
|
error in <...>/invalid-optional-attr.zeek, line 8: &optional is only valid for record fields (&optional)
|
||||||
error in <...>/invalid-optional-attr.zeek, line 11: &optional is only valid for record fields (&optional)
|
error in <...>/invalid-optional-attr.zeek, line 11: &optional is only valid for record fields (&optional)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# Invalid on globals
|
# Invalid on globals
|
||||||
global a: int &optional;
|
global a: int &optional;
|
||||||
|
|
||||||
# TODO: Invalid on parameters
|
# Invalid on parameters
|
||||||
function f(a: int &optional)
|
function f(a: int &optional)
|
||||||
{
|
{
|
||||||
# Invalid in locals
|
# Invalid in locals
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue