Skip to content

Commit e7ff290

Browse files
authored
Fix ccall with no supplied varargs (#102)
Just an off-by-one in desugaring's argument counting. Test case from Mmap.jl: ``` ccall(:fcntl, Cint, (RawFD, Cint, Cint...), s, F_GETFL) ```
1 parent 77eb96f commit e7ff290

File tree

2 files changed

+25
-11
lines changed

2 files changed

+25
-11
lines changed

src/desugaring.jl

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1749,28 +1749,26 @@ function expand_ccall(ctx, ex)
17491749
end
17501750
arg_types = children(arg_type_tuple)
17511751
vararg_type = nothing
1752+
num_required_args = length(arg_types)
17521753
if length(arg_types) >= 1
17531754
va = arg_types[end]
17541755
if kind(va) == K"..."
17551756
@chk numchildren(va) == 1
17561757
# Ok: vararg function
17571758
vararg_type = va
1759+
if length(arg_types) <= 1
1760+
throw(LoweringError(vararg_type, "C ABI prohibits vararg without one required argument"))
1761+
else
1762+
num_required_args = length(arg_types) - 1
1763+
end
17581764
end
17591765
end
17601766
# todo: use multi-range errors here
1761-
if length(args) < length(arg_types)
1767+
if length(args) < num_required_args
17621768
throw(LoweringError(ex, "Too few arguments in ccall compared to argument types"))
17631769
elseif length(args) > length(arg_types) && isnothing(vararg_type)
17641770
throw(LoweringError(ex, "More arguments than types in ccall"))
17651771
end
1766-
if isnothing(vararg_type)
1767-
num_required_args = 0
1768-
else
1769-
num_required_args = length(arg_types) - 1
1770-
if num_required_args < 1
1771-
throw(LoweringError(vararg_type, "C ABI prohibits vararg without one required argument"))
1772-
end
1773-
end
17741772
sctx = with_stmts(ctx)
17751773
expanded_types = SyntaxList(ctx)
17761774
for (i, argt) in enumerate(arg_types)
@@ -1845,7 +1843,7 @@ function expand_ccall(ctx, ex)
18451843
expanded_types...
18461844
]
18471845
]
1848-
num_required_args::K"Integer"
1846+
(isnothing(vararg_type) ? 0 : num_required_args)::K"Integer"
18491847
if isnothing(cconv)
18501848
"ccall"::K"Symbol"
18511849
else

test/misc_ir.jl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ end
396396
24 (return %₂₃)
397397

398398
########################################
399-
# @ccall lowering with varargs and gc_safe
399+
# @ccall lowering with gc_safe
400400
@ccall foo(x::X; y::Y)::R gc_safe=true
401401
#---------------------
402402
1 JuliaLowering.Base
@@ -424,6 +424,22 @@ end
424424
23 (foreigncall :foo (static_eval TestMod.R) (static_eval (call core.svec TestMod.X TestMod.Y)) 1 :($(QuoteNode((:ccall, 0x0000, true)))) %₁₅ %₂₀ %₂₁ %₂₂)
425425
24 (return %₂₃)
426426

427+
########################################
428+
# non-macro ccall with vararg in signature, but none provided
429+
ccall(:fcntl, Cint, (RawFD, Cint, Cint...), s, F_GETFL)
430+
#---------------------
431+
1 TestMod.RawFD
432+
2 TestMod.Cint
433+
3 TestMod.Cint
434+
4 TestMod.s
435+
5 (call top.cconvert %%₄)
436+
6 TestMod.F_GETFL
437+
7 (call top.cconvert %%₆)
438+
8 (call top.unsafe_convert %%₅)
439+
9 (call top.unsafe_convert %%₇)
440+
10 (foreigncall :fcntl (static_eval TestMod.Cint) (static_eval (call core.svec TestMod.RawFD TestMod.Cint TestMod.Cint)) 2 :ccall %%%%₇)
441+
11 (return %₁₀)
442+
427443
########################################
428444
# Error: No return annotation on @ccall
429445
@ccall strlen("foo"::Cstring)

0 commit comments

Comments
 (0)