From 83bca23d4a55db63d3e1761ee88c9a94dac30e53 Mon Sep 17 00:00:00 2001 From: skye Date: Sun, 8 Mar 2026 16:51:27 -0400 Subject: [PATCH] libexpr/primops: Avoid Value default construction in primop_removeAttrs This makes the removal vector a vector of Symbols instead of Attrs, and uses a custom Compare to still be able to std::set_difference them. std::ranges::set_difference **should** be the perfect function for this, but because for some reason it spuriously requires `std::indirectly_copyable`, I can't use it here. This defficiency has bee recognized before [here](https://github.com/cplusplus/papers/issues/1021), but no one has driven the fix forward. Part of #744 Change-Id: I6d2c016ea41e033bf38836f859541b506a6a6964 --- lix/libexpr/primops.cc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lix/libexpr/primops.cc b/lix/libexpr/primops.cc index 92f14c3bf..f09decb15 100644 --- a/lix/libexpr/primops.cc +++ b/lix/libexpr/primops.cc @@ -1974,7 +1974,7 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) We keep them as Attrs instead of Symbols so std::set_difference can be used to remove them from attrs[0]. */ // 64: large enough to fit the attributes of a derivation - boost::container::small_vector names; + boost::container::small_vector names; names.reserve(args[1]->listSize()); for (auto & elem : args[1]->listItems()) { state.forceStringNoCtx( @@ -1982,7 +1982,7 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) noPos, "while evaluating the values of the second argument passed to builtins.removeAttrs" ); - names.emplace_back(state.ctx.symbols.create(elem.str()), Value()); + names.push_back(state.ctx.symbols.create(elem.str())); } std::sort(names.begin(), names.end()); @@ -1991,9 +1991,16 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) vector. */ auto attrs = state.ctx.buildBindings(args[0]->attrs()->size()); std::set_difference( - args[0]->attrs()->begin(), args[0]->attrs()->end(), - names.begin(), names.end(), - std::back_inserter(attrs)); + args[0]->attrs()->begin(), + args[0]->attrs()->end(), + names.begin(), + names.end(), + std::back_inserter(attrs), + overloaded{ + [](const Attr & a, const Symbol & s) { return a.name < s; }, + [](const Symbol & s, const Attr & a) { return s < a.name; } + } + ); v = {NewValueAs::attrs, attrs.alreadySorted()}; }