Capturing warnings inside generated functions

Is there a way to capture logging messages (e.g. warnings) issued during compilation, for example from inside a generated function? For example

julia> using Logging

julia> @generated foo() = @warn "this warning is emitted during compilation"
foo (generic function with 1 method)

julia> with_logger(NullLogger()) do; foo(); end
┌ Warning: this warning is emitted during compilation
└ @ Main REPL[18]:1

this doesn’t capture the warning, because it’s emitted before running the body of the do-block, during compilation.

Bonus points for a solution which works with Test.@test_warn.

Very hacky workaround, but one approach would be to use eval or to store the function in an untyped container:

julia> using Logging

julia> @generated foo() = @warn "this warning is emitted during compilation";

julia> with_logger(NullLogger()) do
           @eval foo()
       end
julia> using Logging

julia> @generated foo() = @warn "this warning is emitted during compilation";

julia> let fv = Ref{Any}(foo)
           with_logger(NullLogger()) do 
               fv[]()
           end
       end

Both solutions help ensure that foo is not compiled at the same time as the do block.

Oh, right, @eval works also with @test_warn:

julia> @generated foo() = @warn "this warning is emitted during compilation"
foo (generic function with 1 method)

julia> @test_warn "this warning is emitted during compilation" @eval foo()

Of course this would fail if the function is called once more:

julia> @test_warn "this warning is emitted during compilation" @eval foo()
Test Failed at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-XG3Q6T6R70.0/build/default-honeycrisp-XG3Q6T6R70-0/julialang/julia-release-1-dot-11/usr/share/julia/stdlib/v1.11/Test/src/Test.jl:896
  Expression: contains_warn(read(fname, String), $(Expr(:escape, "this warning is emitted during compilation")))

ERROR: There was an error during testing

but inside tests execution is generally deterministic, so that shouldn’t be a problem. Need only to see if using @eval in these tests has drawbacks, hopefully not. Thanks!

1 Like

And of course my hope was ill posed. But wrapping the function in Ref{Any} seems to work well, so I think I’ll go with that solution, thanks!

julia> @testset begin
           @generated foo() = @warn "this warning is emitted during compilation"
           f = Ref{Any}(foo)
           @test_warn "this warning is emitted during compilation" f[]()
       end;
Test Summary: | Pass  Total  Time
test set      |    1      1  0.0s
1 Like