diff --git a/base/reflection.jl b/base/reflection.jl index ee96b24dc6b96..706570303262c 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -1084,13 +1084,25 @@ function may_invoke_generator(method::Method, @nospecialize(atypes), sparams::Si end end end - for i = 1:length(at.parameters) + non_va_args = method.isva ? method.nargs - 1 : method.nargs + for i = 1:non_va_args if !isdispatchelem(at.parameters[i]) if (ast_slotflag(code, 1 + i + nsparams) & SLOT_USED) != 0 return false end end end + if method.isva + # If the va argument is used, we need to ensure that all arguments that + # contribute to the va tuple are dispatchelemes + if (ast_slotflag(code, 1 + method.nargs + nsparams) & SLOT_USED) != 0 + for i = (non_va_args+1):length(at.parameters) + if !isdispatchelem(at.parameters[i]) + return false + end + end + end + end return true end diff --git a/test/staged.jl b/test/staged.jl index 26e3dace1994b..4a953ffae33b8 100644 --- a/test/staged.jl +++ b/test/staged.jl @@ -304,3 +304,18 @@ end :(global x33243 = 2) end @test_throws ErrorException f33243() + +# https://github.com/JuliaDebug/CassetteOverlay.jl/issues/12 +# generated function with varargs and unfortunately placed unused slot +@generated function f_vararg_generated(args...) + :($args) +end +g_vararg_generated() = f_vararg_generated((;), (;), Base.inferencebarrier((;))) +let tup = g_vararg_generated() + @test !any(==(Any), tup) + # This is just to make sure that the test is actually testing what we want - + # the test only works if there's an unused that matches the position of the + # inferencebarrier argument above (N.B. the generator function itself + # shifts everything over by 1) + @test code_lowered(first(methods(f_vararg_generated)).generator.gen)[1].slotflags[5] == UInt8(0x00) +end