diff --git a/src/Attr.cc b/src/Attr.cc index 5a83d0501b..472fbdffe2 100644 --- a/src/Attr.cc +++ b/src/Attr.cc @@ -57,10 +57,11 @@ void Attr::AddTag(ODesc* d) const d->Add(attr_name(Tag())); } -Attributes::Attributes(attr_list* a, BroType* t) +Attributes::Attributes(attr_list* a, BroType* t, bool arg_in_record) { attrs = new attr_list(a->length()); type = t->Ref(); + in_record = arg_in_record; SetLocationInfo(&start_location, &end_location); @@ -199,7 +200,7 @@ void Attributes::CheckAttr(Attr* a) { BroType* atype = a->AttrExpr()->Type(); - if ( type->Tag() != TYPE_TABLE || type->IsSet() ) + if ( type->Tag() != TYPE_TABLE || (type->IsSet() && ! in_record) ) { if ( ! same_type(atype, type) ) a->AttrExpr()->Error("&default value has inconsistent type", type); @@ -208,18 +209,30 @@ void Attributes::CheckAttr(Attr* a) TableType* tt = type->AsTableType(); - if ( ! same_type(atype, tt->YieldType()) ) + if ( ! in_record ) { - // It can still be a default function. - if ( atype->Tag() == TYPE_FUNC ) + // &default applies to the type itself. + if ( ! same_type(atype, tt->YieldType()) ) { - FuncType* f = atype->AsFuncType(); - if ( ! f->CheckArgs(tt->IndexTypes()) || - ! same_type(f->YieldType(), tt->YieldType()) ) - Error("&default function type clash"); + // It can still be a default function. + if ( atype->Tag() == TYPE_FUNC ) + { + FuncType* f = atype->AsFuncType(); + if ( ! f->CheckArgs(tt->IndexTypes()) || + ! same_type(f->YieldType(), tt->YieldType()) ) + Error("&default function type clash"); + } + else + Error("&default value has inconsistent type"); } - else - Error("&default value has inconsistent type"); + } + else + { + // &default applies to record field. + if ( ! same_type(atype, type) && + ! (atype->Tag() == TYPE_TABLE && atype->AsTableType()->IsUnspecifiedTable()) ) + Error("&default value has inconsistent type"); + break; } } break; diff --git a/src/Attr.h b/src/Attr.h index 73fb101841..4191ffa911 100644 --- a/src/Attr.h +++ b/src/Attr.h @@ -62,7 +62,7 @@ protected: // Manages a collection of attributes. class Attributes : public BroObj { public: - Attributes(attr_list* a, BroType* t); + Attributes(attr_list* a, BroType* t, bool in_record); ~Attributes(); void AddAttr(Attr* a); @@ -87,6 +87,7 @@ protected: BroType* type; attr_list* attrs; + bool in_record; }; #endif diff --git a/src/Expr.cc b/src/Expr.cc index dbfca7c9cb..1c26039a6d 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -3400,7 +3400,7 @@ TableConstructorExpr::TableConstructorExpr(ListExpr* constructor_list, SetError("values in table(...) constructor do not specify a table"); } - attrs = arg_attrs ? new Attributes(arg_attrs, type) : 0; + attrs = arg_attrs ? new Attributes(arg_attrs, type, false) : 0; } Val* TableConstructorExpr::Eval(Frame* f) const @@ -3466,7 +3466,7 @@ SetConstructorExpr::SetConstructorExpr(ListExpr* constructor_list, else if ( type->Tag() != TYPE_TABLE || ! type->AsTableType()->IsSet() ) SetError("values in set(...) constructor do not specify a set"); - attrs = arg_attrs ? new Attributes(arg_attrs, type) : 0; + attrs = arg_attrs ? new Attributes(arg_attrs, type, false) : 0; } Val* SetConstructorExpr::Eval(Frame* f) const diff --git a/src/StateAccess.cc b/src/StateAccess.cc index 17f702f07e..74481a155a 100644 --- a/src/StateAccess.cc +++ b/src/StateAccess.cc @@ -935,7 +935,7 @@ void NotifierRegistry::Register(ID* id, NotifierRegistry::Notifier* notifier) attr_list* a = new attr_list; Attr* attr = new Attr(ATTR_TRACKED); a->append(attr); - id->SetAttrs(new Attributes(a, id->Type())); + id->SetAttrs(new Attributes(a, id->Type(), false)); Unref(attr); } diff --git a/src/Type.cc b/src/Type.cc index ce3bbc52af..81994a19a8 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -680,10 +680,10 @@ bool FuncType::DoUnserialize(UnserialInfo* info) return UNSERIALIZE(&is_event); } -TypeDecl::TypeDecl(BroType* t, const char* i, attr_list* arg_attrs) +TypeDecl::TypeDecl(BroType* t, const char* i, attr_list* arg_attrs, bool in_record) { type = t; - attrs = arg_attrs ? new Attributes(arg_attrs, t) : 0; + attrs = arg_attrs ? new Attributes(arg_attrs, t, in_record) : 0; id = i; } diff --git a/src/Type.h b/src/Type.h index fe4f7a5eb5..bf037e2ed6 100644 --- a/src/Type.h +++ b/src/Type.h @@ -361,7 +361,7 @@ protected: class TypeDecl { public: - TypeDecl(BroType* t, const char* i, attr_list* attrs = 0); + TypeDecl(BroType* t, const char* i, attr_list* attrs = 0, bool in_record = false); ~TypeDecl(); const Attr* FindAttr(attr_tag a) const diff --git a/src/Var.cc b/src/Var.cc index 04ef78c14c..0c2be25711 100644 --- a/src/Var.cc +++ b/src/Var.cc @@ -107,7 +107,7 @@ static void make_var(ID* id, BroType* t, init_class c, Expr* init, id->SetType(t); if ( attr ) - id->AddAttrs(new Attributes(attr, t)); + id->AddAttrs(new Attributes(attr, t, false)); if ( id->FindAttr(ATTR_PERSISTENT) || id->FindAttr(ATTR_SYNCHRONIZED) ) { @@ -221,7 +221,7 @@ void add_type(ID* id, BroType* t, attr_list* attr, int /* is_event */) id->MakeType(); if ( attr ) - id->SetAttrs(new Attributes(attr, t)); + id->SetAttrs(new Attributes(attr, t, false)); } void begin_func(ID* id, const char* module_name, function_flavor flavor, diff --git a/src/parse.y b/src/parse.y index a982935b2b..370d1e0571 100644 --- a/src/parse.y +++ b/src/parse.y @@ -100,6 +100,7 @@ extern Expr* g_curr_debug_expr; Expr* bro_this = 0; int in_init = 0; +int in_record = 0; bool in_debug = false; bool resolving_global_ID = false; @@ -704,10 +705,10 @@ type: $$ = new SetType($3, 0); } - | TOK_RECORD '{' type_decl_list '}' + | TOK_RECORD '{' { ++in_record; } type_decl_list { --in_record; } '}' { - set_location(@1, @4); - $$ = new RecordType($3); + set_location(@1, @5); + $$ = new RecordType($4); } | TOK_UNION '{' type_list '}' @@ -805,7 +806,7 @@ type_decl: TOK_ID ':' type opt_attr ';' { set_location(@1, @5); - $$ = new TypeDecl($3, $1, $4); + $$ = new TypeDecl($3, $1, $4, (in_record > 0)); } ; diff --git a/testing/btest/Baseline/language.rec-table-default/output b/testing/btest/Baseline/language.rec-table-default/output new file mode 100644 index 0000000000..a1531d06ee --- /dev/null +++ b/testing/btest/Baseline/language.rec-table-default/output @@ -0,0 +1,14 @@ +{ +[foo] = T +} +{ + +} +{ +A, +B, +C +} +{ + +} diff --git a/testing/btest/language/rec-table-default.bro b/testing/btest/language/rec-table-default.bro new file mode 100644 index 0000000000..1473933e6a --- /dev/null +++ b/testing/btest/language/rec-table-default.bro @@ -0,0 +1,19 @@ + +# @TEST-EXEC: bro %INPUT >output 2>&1 +# @TEST-EXEC: btest-diff output + +type X: record { + a: table[string] of bool &default=table( ["foo"] = T ); + b: table[string] of bool &default=table(); + c: set[string] &default=set("A", "B", "C"); + d: set[string] &default=set(); +}; + +global x: X; +global y: table[string] of bool &default=T; + +print x$a; +print x$b; +print x$c; +print x$d; +