https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing
As a heuristic, Julia avoids automatically specializing on argument type parameters in three specific cases:
Type,Function, andVararg. Julia will always specialize when the argument is used within the method, but not if the argument is just passed through to another function.
So your non-allocating example uses f, and thus the method is (presumably) specialized for f, while the allocating examples just pass it through, so specialization is avoided.
Be aware that adding the where annotation for f will lead to compilation for each new f.