Skip to content

Commit 68fcf0c

Browse files
KenoKristofferC
authored andcommitted
Fix generator-invocation legality check for varargs generators (#47739)
This code was introduced by me back in #31025 to speed up evaluation of generated functions that didn't make use of all of their arguments to make generation decisions. However, it neglected to take into account the possibility that the generator could be varargs. As a result, an unfortunate coincidence of an unused slot in the correct position could have allowed expansion of generators that were not supposed to be expandable. This can cause incorrect inference with all the usual consequences. However, fortunately this coincidence appears to be pretty rare. Fixes JuliaDebug/CassetteOverlay.jl#12 (cherry picked from commit 328dd57)
1 parent f66b5a3 commit 68fcf0c

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

base/reflection.jl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1155,13 +1155,25 @@ function may_invoke_generator(method::Method, @nospecialize(atype), sparams::Sim
11551155
end
11561156
end
11571157
end
1158-
for i = 1:length(at.parameters)
1158+
non_va_args = method.isva ? method.nargs - 1 : method.nargs
1159+
for i = 1:non_va_args
11591160
if !isdispatchelem(at.parameters[i])
11601161
if (ast_slotflag(code, 1 + i + nsparams) & SLOT_USED) != 0
11611162
return false
11621163
end
11631164
end
11641165
end
1166+
if method.isva
1167+
# If the va argument is used, we need to ensure that all arguments that
1168+
# contribute to the va tuple are dispatchelemes
1169+
if (ast_slotflag(code, 1 + method.nargs + nsparams) & SLOT_USED) != 0
1170+
for i = (non_va_args+1):length(at.parameters)
1171+
if !isdispatchelem(at.parameters[i])
1172+
return false
1173+
end
1174+
end
1175+
end
1176+
end
11651177
return true
11661178
end
11671179

test/staged.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,3 +305,18 @@ end
305305
end
306306
@test f33243() === 2
307307
@test x33243 === 2
308+
309+
# https://github.com/JuliaDebug/CassetteOverlay.jl/issues/12
310+
# generated function with varargs and unfortunately placed unused slot
311+
@generated function f_vararg_generated(args...)
312+
:($args)
313+
end
314+
g_vararg_generated() = f_vararg_generated((;), (;), Base.inferencebarrier((;)))
315+
let tup = g_vararg_generated()
316+
@test !any(==(Any), tup)
317+
# This is just to make sure that the test is actually testing what we want -
318+
# the test only works if there's an unused that matches the position of the
319+
# inferencebarrier argument above (N.B. the generator function itself
320+
# shifts everything over by 1)
321+
@test code_lowered(first(methods(f_vararg_generated)).generator.gen)[1].slotflags[5] == UInt8(0x00)
322+
end

0 commit comments

Comments
 (0)