diff --git a/src/Expr.cc b/src/Expr.cc index ad6c18432c..ce9ae47868 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -4366,6 +4366,11 @@ LambdaExpr::LambdaExpr(std::unique_ptr arg_ing, id->SetConst(); } +Scope* LambdaExpr::GetScope() const + { + return ingredients->scope.get(); + } + IntrusivePtr LambdaExpr::Eval(Frame* f) const { auto lamb = make_intrusive( diff --git a/src/Expr.h b/src/Expr.h index 95c1167abe..69ae43b4be 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -61,6 +61,7 @@ extern const char* expr_name(BroExprTag t); template class IntrusivePtr; class Stmt; class Frame; +class Scope; class ListExpr; class NameExpr; class IndexExpr; @@ -813,6 +814,8 @@ public: IntrusivePtr Eval(Frame* f) const override; TraversalCode Traverse(TraversalCallback* cb) const override; + Scope* GetScope() const; + protected: void ExprDescribe(ODesc* d) const override; diff --git a/src/ID.cc b/src/ID.cc index f8d4c97bd1..c7228a6901 100644 --- a/src/ID.cc +++ b/src/ID.cc @@ -12,7 +12,6 @@ #include "Scope.h" #include "Type.h" #include "File.h" -#include "Scope.h" #include "Traverse.h" #include "Val.h" #include "zeekygen/Manager.h" diff --git a/src/Var.cc b/src/Var.cc index d49323b7f3..461de5e99f 100644 --- a/src/Var.cc +++ b/src/Var.cc @@ -419,32 +419,25 @@ void begin_func(ID* id, const char* module_name, function_flavor flavor, class OuterIDBindingFinder : public TraversalCallback { public: OuterIDBindingFinder(Scope* s) - : scope(s) { } + { + scopes.emplace_back(s); + } virtual TraversalCode PreExpr(const Expr*); virtual TraversalCode PostExpr(const Expr*); - Scope* scope; + std::vector scopes; vector outer_id_references; - int lambda_depth = 0; - // Note: think we really ought to toggle this to false to prevent - // considering locals within inner-lambdas as "outer", but other logic - // for "selective cloning" and locating IDs in the closure chain may - // depend on current behavior and also needs to be changed. - bool search_inner_lambdas = true; }; TraversalCode OuterIDBindingFinder::PreExpr(const Expr* expr) { if ( expr->Tag() == EXPR_LAMBDA ) - ++lambda_depth; - - if ( lambda_depth > 0 && ! search_inner_lambdas ) - // Don't inspect the bodies of inner lambdas as they will have their - // own traversal to find outer IDs and we don't want to detect - // references to local IDs inside and accidentally treat them as - // "outer" since they can't be found in current scope. + { + auto le = static_cast(expr); + scopes.emplace_back(le->GetScope()); return TC_CONTINUE; + } if ( expr->Tag() != EXPR_NAME ) return TC_CONTINUE; @@ -454,8 +447,11 @@ TraversalCode OuterIDBindingFinder::PreExpr(const Expr* expr) if ( e->Id()->IsGlobal() ) return TC_CONTINUE; - if ( scope->Lookup(e->Id()->Name()) ) - return TC_CONTINUE; + for ( const auto& scope : scopes ) + if ( scope->Lookup(e->Id()->Name()) ) + // Shadowing is not allowed, so if it's found at inner scope, it's + // not something we have to worry about also being at outer scope. + return TC_CONTINUE; outer_id_references.push_back(e); return TC_CONTINUE; @@ -464,10 +460,7 @@ TraversalCode OuterIDBindingFinder::PreExpr(const Expr* expr) TraversalCode OuterIDBindingFinder::PostExpr(const Expr* expr) { if ( expr->Tag() == EXPR_LAMBDA ) - { - --lambda_depth; - assert(lambda_depth >= 0); - } + scopes.pop_back(); return TC_CONTINUE; } diff --git a/testing/btest/Baseline/language.lambda-nested-copy/out b/testing/btest/Baseline/language.lambda-nested-copy/out new file mode 100644 index 0000000000..b963e085f3 --- /dev/null +++ b/testing/btest/Baseline/language.lambda-nested-copy/out @@ -0,0 +1,2 @@ +106 +106 diff --git a/testing/btest/language/lambda-nested-copy.zeek b/testing/btest/language/lambda-nested-copy.zeek new file mode 100644 index 0000000000..6cf0e6952a --- /dev/null +++ b/testing/btest/language/lambda-nested-copy.zeek @@ -0,0 +1,19 @@ +# @TEST-EXEC: zeek -b %INPUT >out +# @TEST-EXEC: btest-diff out + +local outer = 100; + +local lambda = function() + { + local inner = function(a: count, b: count, c: count, d: count, e: count, f: count) + { + print outer + f; + }; + + inner(1, 2, 3, 4, 5, 6); + }; + +lambda(); + +local copyLambda = copy(copy(copy(lambda))); +copyLambda();