From a9d21f7dd19a8fa97173394d050a24107b950755 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Mon, 9 Jul 2018 23:49:53 +0200 Subject: [PATCH 1/6] Fixes for Julia 0.7. Drop 0.5 and 0.6. Mostly straightforward, but note that (probably due to https://github.com/JuliaLang/julia/issues/26297), llvmcall has to be imported from Base in order to avoid the error 'error compiling assume: error statically evaluating llvm IR argument'. Also note that cfunction calls have been replaced with ccalls to jl_function_ptr, while they should probably be replaced with cfunction macro calls. The problem is however that the cfunction macro expects a literal tuple for the argument types. --- .travis.yml | 3 +- REQUIRE | 2 +- appveyor.yml | 6 +-- src/FunctionWrappers.jl | 85 +++++++++++++++++++---------------------- test/runtests.jl | 20 +++++----- 5 files changed, 52 insertions(+), 64 deletions(-) diff --git a/.travis.yml b/.travis.yml index 66f2d04..34bfce9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,7 @@ os: - linux - osx julia: - - 0.5 - - 0.6 + - 0.7 - nightly after_success: - julia -e 'cd(Pkg.dir("FunctionWrappers")); Pkg.add("Coverage"); using Coverage; Codecov.submit(process_folder())' diff --git a/REQUIRE b/REQUIRE index 94237c0..cdbb2dc 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1 +1 @@ -julia 0.5 +julia 0.7-alpha diff --git a/appveyor.yml b/appveyor.yml index 48d7358..fb5a3a2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,9 +1,7 @@ environment: matrix: - - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe" - - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe" - - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe" - - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe" + - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.7/julia-0.7-latest-win32.exe" + - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.7/julia-0.7-latest-win64.exe" - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe" - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe" diff --git a/src/FunctionWrappers.jl b/src/FunctionWrappers.jl index 3f3483e..f8b2334 100644 --- a/src/FunctionWrappers.jl +++ b/src/FunctionWrappers.jl @@ -4,96 +4,89 @@ __precompile__(true) module FunctionWrappers +using Base: llvmcall + # Used to bypass NULL check @inline function assume(v::Bool) - Base.llvmcall(("declare void @llvm.assume(i1)", + llvmcall(("declare void @llvm.assume(i1)", """ %v = trunc i8 %0 to i1 call void @llvm.assume(i1 %v) ret void - """), Void, Tuple{Bool}, v) + """), Cvoid, Tuple{Bool}, v) end -@static if isdefined(Base, Symbol("@nospecialize")) - is_singleton(@nospecialize(T)) = isdefined(T, :instance) -else - is_singleton(T::ANY) = isdefined(T, :instance) -end +is_singleton(@nospecialize(T)) = isdefined(T, :instance) # Convert return type and generates cfunction signatures Base.@pure map_rettype(T) = - (isbits(T) || T === Any || is_singleton(T)) ? T : Ref{T} + (isbitstype(T) || T === Any || is_singleton(T)) ? T : Ref{T} Base.@pure function map_cfunc_argtype(T) if is_singleton(T) return Ref{T} end - return (isbits(T) || T === Any) ? T : Ref{T} + return (isbitstype(T) || T === Any) ? T : Ref{T} end Base.@pure function map_argtype(T) if is_singleton(T) return Any end - return (isbits(T) || T === Any) ? T : Any + return (isbitstype(T) || T === Any) ? T : Any end Base.@pure get_cfunc_argtype(Obj, Args) = Tuple{Ref{Obj}, (map_cfunc_argtype(Arg) for Arg in Args.parameters)...} # Call wrapper since `cfunction` does not support non-function # or closures -if VERSION >= v"0.6.0" - # Can in princeple be lower but 0.6 doesn't warn on this so it doesn't matter - eval(parse("struct CallWrapper{Ret} <: Function end")) -else - include_string("immutable CallWrapper{Ret} <: Function end") -end -(::CallWrapper{Ret}){Ret}(f, args...)::Ret = f(args...) +struct CallWrapper{Ret} <: Function end +(::CallWrapper{Ret})(f, args...) where {Ret} = convert(Ret, f(args...)) # Specialized wrapper for for nargs in 0:128 - @eval (::CallWrapper{Ret}){Ret}(f, $((Symbol("arg", i) for i in 1:nargs)...))::Ret = - f($((Symbol("arg", i) for i in 1:nargs)...)) + @eval function (::CallWrapper{Ret})(f, $((Symbol("arg", i) for i in 1:nargs)...)) where Ret + convert(Ret, f($((Symbol("arg", i) for i in 1:nargs)...))) + end end -let ex = if VERSION >= v"0.6.0" - # Can in princeple be lower but 0.6 doesn't warn on this so it doesn't matter - parse("mutable struct FunctionWrapper{Ret,Args<:Tuple} end") -else - parse("type FunctionWrapper{Ret,Args<:Tuple} end") -end - ex.args[3] = quote - ptr::Ptr{Void} - objptr::Ptr{Void} - obj - objT - function (::Type{FunctionWrapper{Ret,Args}}){Ret,Args,objT}(obj::objT) - objref = Base.cconvert(Ref{objT}, obj) - new{Ret,Args}(cfunction(CallWrapper{Ret}(), map_rettype(Ret), - get_cfunc_argtype(objT, Args)), - Base.unsafe_convert(Ref{objT}, objref), objref, objT) - end - (::Type{FunctionWrapper{Ret,Args}}){Ret,Args}(obj::FunctionWrapper{Ret,Args}) = obj +mutable struct FunctionWrapper{Ret,Args<:Tuple} + ptr::Ptr{Cvoid} + objptr::Ptr{Cvoid} + obj + objT + + function FunctionWrapper{Ret,Args}(obj::objT) where {Ret,Args,objT} + objref = Base.cconvert(Ref{objT}, obj) + # ptr = cfunction( + # CallWrapper{Ret}(), map_rettype(Ret), + # get_cfunc_argtype(objT, Args)) + # FIXME: use @cfunction (problem: it expects a literal tuple for the argument types) + ptr = ccall(:jl_function_ptr, Ptr{Cvoid}, (Any, Any, Any), CallWrapper{Ret}(), map_rettype(Ret), get_cfunc_argtype(objT, Args)) + new{Ret,Args}(ptr, Base.unsafe_convert(Ref{objT}, objref), objref, objT) end - eval(ex) + + FunctionWrapper{Ret,Args}(obj::FunctionWrapper{Ret,Args}) where {Ret, Args} = obj end -Base.convert{T<:FunctionWrapper}(::Type{T}, obj) = T(obj) -Base.convert{T<:FunctionWrapper}(::Type{T}, obj::T) = obj +Base.convert(::Type{T}, obj) where {T<:FunctionWrapper} = T(obj) +Base.convert(::Type{T}, obj::T) where {T<:FunctionWrapper} = obj -@noinline function reinit_wrapper{Ret,Args}(f::FunctionWrapper{Ret,Args}) +@noinline function reinit_wrapper(f::FunctionWrapper{Ret,Args}) where {Ret,Args} objref = f.obj objT = f.objT - ptr = cfunction(CallWrapper{Ret}(), map_rettype(Ret), - get_cfunc_argtype(objT, Args)) + # ptr = cfunction(CallWrapper{Ret}(), map_rettype(Ret), + # get_cfunc_argtype(objT, Args)) + # FIXME: use @cfunction (problem: it expects a literal tuple for the argument types) + ptr = ccall(:jl_function_ptr, Ptr{Cvoid}, (Any, Any, Any), CallWrapper{Ret}(), map_rettype(Ret), get_cfunc_argtype(objT, Args)) f.ptr = ptr f.objptr = Base.unsafe_convert(Ref{objT}, objref) return ptr end -@generated function do_ccall{Ret,Args}(f::FunctionWrapper{Ret,Args}, args::Args) +@generated function do_ccall(f::FunctionWrapper{Ret,Args}, args::Args) where {Ret,Args} # Has to be generated since the arguments type of `ccall` does not allow # anything other than tuple (i.e. `@pure` function doesn't work). quote - $(Expr(:meta, :inline)) + Base.@_inline_meta ptr = f.ptr if ptr == C_NULL # For precompile support @@ -102,7 +95,7 @@ end assume(ptr != C_NULL) objptr = f.objptr ccall(ptr, $(map_rettype(Ret)), - (Ptr{Void}, $((map_argtype(Arg) for Arg in Args.parameters)...)), + (Ptr{Cvoid}, $((map_argtype(Arg) for Arg in Args.parameters)...)), objptr, $((:(args[$i]) for i in 1:length(Args.parameters))...)) end end diff --git a/test/runtests.jl b/test/runtests.jl index 1658bf7..242b4e9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,15 +2,13 @@ import FunctionWrappers import FunctionWrappers: FunctionWrapper -using Base.Test +using Test -if VERSION >= v"0.6.0" - # Can in princeple be lower but 0.6 doesn't warn on this so it doesn't matter - eval(parse("struct CallbackF64 f::FunctionWrapper{Float64,Tuple{Int}} end")) -else - eval(parse("immutable CallbackF64 f::FunctionWrapper{Float64,Tuple{Int}} end")) +struct CallbackF64 + f::FunctionWrapper{Float64,Tuple{Int}} end (cb::CallbackF64)(v) = cb.f(v) + gen_closure(x) = y->x + y @testset "As field" begin @@ -56,10 +54,10 @@ end @test FunctionWrappers.identityAnyAny(1) === 1 end -@testset "Void" begin - identityVoidVoid = FunctionWrapper{Void,Tuple{Void}}(identity) - @test identityVoidVoid(nothing) === nothing +@testset "Nothing" begin + identityNothingNothing = FunctionWrapper{Nothing,Tuple{Nothing}}(identity) + @test identityNothingNothing(nothing) === nothing f1 = (a, b)->b - fIntVoidInt = FunctionWrapper{Int,Tuple{Void,Int}}(f1) - @test fIntVoidInt(nothing, 1) === 1 + fIntNothingInt = FunctionWrapper{Int,Tuple{Nothing,Int}}(f1) + @test fIntNothingInt(nothing, 1) === 1 end From 8b185398901369a6dc8e3c6ae51cf1f57eefd429 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Fri, 20 Jul 2018 15:40:29 -0400 Subject: [PATCH 2/6] Just use Base.llvmcall again now that https://github.com/JuliaLang/julia/pull/28172 is fixed. --- src/FunctionWrappers.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/FunctionWrappers.jl b/src/FunctionWrappers.jl index f8b2334..7ea9f6e 100644 --- a/src/FunctionWrappers.jl +++ b/src/FunctionWrappers.jl @@ -4,11 +4,9 @@ __precompile__(true) module FunctionWrappers -using Base: llvmcall - # Used to bypass NULL check @inline function assume(v::Bool) - llvmcall(("declare void @llvm.assume(i1)", + Base.llvmcall(("declare void @llvm.assume(i1)", """ %v = trunc i8 %0 to i1 call void @llvm.assume(i1 %v) From c08bdbab95a82a8db070b19822fd00b09b9c66c2 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Tue, 10 Jul 2018 22:16:19 +0200 Subject: [PATCH 3/6] Rebase rdeits/v0.7 onto tk/julia-0.7. --- src/FunctionWrappers.jl | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/FunctionWrappers.jl b/src/FunctionWrappers.jl index 7ea9f6e..4e33ae2 100644 --- a/src/FunctionWrappers.jl +++ b/src/FunctionWrappers.jl @@ -34,16 +34,11 @@ end Base.@pure get_cfunc_argtype(Obj, Args) = Tuple{Ref{Obj}, (map_cfunc_argtype(Arg) for Arg in Args.parameters)...} -# Call wrapper since `cfunction` does not support non-function -# or closures -struct CallWrapper{Ret} <: Function end -(::CallWrapper{Ret})(f, args...) where {Ret} = convert(Ret, f(args...)) - -# Specialized wrapper for -for nargs in 0:128 - @eval function (::CallWrapper{Ret})(f, $((Symbol("arg", i) for i in 1:nargs)...)) where Ret - convert(Ret, f($((Symbol("arg", i) for i in 1:nargs)...))) - end +@generated function make_cfunction(obj::objT, ::Type{Ret}, ::Type{Args}) where {objT,Ret,Args} + :(@cfunction( + $(Expr(:$, obj)), + map_rettype(Ret), + (Ref{objT}, $([:(map_cfunc_argtype($Arg)) for Arg in Args.parameters]...)))) end mutable struct FunctionWrapper{Ret,Args<:Tuple} @@ -51,18 +46,13 @@ mutable struct FunctionWrapper{Ret,Args<:Tuple} objptr::Ptr{Cvoid} obj objT - function FunctionWrapper{Ret,Args}(obj::objT) where {Ret,Args,objT} objref = Base.cconvert(Ref{objT}, obj) - # ptr = cfunction( - # CallWrapper{Ret}(), map_rettype(Ret), - # get_cfunc_argtype(objT, Args)) - # FIXME: use @cfunction (problem: it expects a literal tuple for the argument types) - ptr = ccall(:jl_function_ptr, Ptr{Cvoid}, (Any, Any, Any), CallWrapper{Ret}(), map_rettype(Ret), get_cfunc_argtype(objT, Args)) + ptr = make_cfunction(obj, Ret, Args) new{Ret,Args}(ptr, Base.unsafe_convert(Ref{objT}, objref), objref, objT) end - FunctionWrapper{Ret,Args}(obj::FunctionWrapper{Ret,Args}) where {Ret, Args} = obj + FunctionWrapper{Ret,Args}(obj::FunctionWrapper{Ret,Args}) where {Ret,Args} = obj end Base.convert(::Type{T}, obj) where {T<:FunctionWrapper} = T(obj) @@ -71,10 +61,7 @@ Base.convert(::Type{T}, obj::T) where {T<:FunctionWrapper} = obj @noinline function reinit_wrapper(f::FunctionWrapper{Ret,Args}) where {Ret,Args} objref = f.obj objT = f.objT - # ptr = cfunction(CallWrapper{Ret}(), map_rettype(Ret), - # get_cfunc_argtype(objT, Args)) - # FIXME: use @cfunction (problem: it expects a literal tuple for the argument types) - ptr = ccall(:jl_function_ptr, Ptr{Cvoid}, (Any, Any, Any), CallWrapper{Ret}(), map_rettype(Ret), get_cfunc_argtype(objT, Args)) + ptr = make_cfunction(obj, Ret, Args) f.ptr = ptr f.objptr = Base.unsafe_convert(Ref{objT}, objref) return ptr From 050d47dcf2e112d49bf2e45a59c73c1c4efc8e90 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Sat, 11 Aug 2018 17:07:47 -0400 Subject: [PATCH 4/6] Partial reimplementation for Julia 1.0 using cfunction macro. --- src/FunctionWrappers.jl | 48 +++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/FunctionWrappers.jl b/src/FunctionWrappers.jl index 4e33ae2..730af90 100644 --- a/src/FunctionWrappers.jl +++ b/src/FunctionWrappers.jl @@ -31,25 +31,43 @@ Base.@pure function map_argtype(T) end return (isbitstype(T) || T === Any) ? T : Any end -Base.@pure get_cfunc_argtype(Obj, Args) = - Tuple{Ref{Obj}, (map_cfunc_argtype(Arg) for Arg in Args.parameters)...} + +# callable that converts output of f to type Ret +struct CallWrapper{Ret, F} + f::F +end + +CallWrapper{Ret}(f::F) where {Ret, F} = CallWrapper{Ret, F}(f) + +(wrapper::CallWrapper{Ret})(args...) where {Ret} = convert(Ret, wrapper.f(args...)) + +for nargs in 0:128 + @eval function (wrapper::CallWrapper{Ret})($((Symbol("arg", i) for i in 1:nargs)...)) where Ret + convert(Ret, wrapper.f($((Symbol("arg", i) for i in 1:nargs)...))) + end +end @generated function make_cfunction(obj::objT, ::Type{Ret}, ::Type{Args}) where {objT,Ret,Args} - :(@cfunction( - $(Expr(:$, obj)), - map_rettype(Ret), - (Ref{objT}, $([:(map_cfunc_argtype($Arg)) for Arg in Args.parameters]...)))) + quote + wrapped = CallWrapper{Ret}(obj) + @cfunction( + $(Expr(:$, :wrapped)), # use $ to create runtime closure over obj + map_rettype(Ret), + ($([:(map_cfunc_argtype($Arg)) for Arg in Args.parameters]...), )) + end end mutable struct FunctionWrapper{Ret,Args<:Tuple} ptr::Ptr{Cvoid} objptr::Ptr{Cvoid} + cfun obj objT function FunctionWrapper{Ret,Args}(obj::objT) where {Ret,Args,objT} - objref = Base.cconvert(Ref{objT}, obj) - ptr = make_cfunction(obj, Ret, Args) - new{Ret,Args}(ptr, Base.unsafe_convert(Ref{objT}, objref), objref, objT) + cfun = make_cfunction(obj, Ret, Args) + ptr = Base.unsafe_convert(Ptr{Cvoid}, Base.cconvert(Ptr{Cvoid}, cfun)) + objptr = Base.unsafe_convert(Ref{objT}, Base.cconvert(Ref{objT}, obj)) + new{Ret,Args}(ptr, objptr, cfun, obj, objT) end FunctionWrapper{Ret,Args}(obj::FunctionWrapper{Ret,Args}) where {Ret,Args} = obj @@ -59,11 +77,13 @@ Base.convert(::Type{T}, obj) where {T<:FunctionWrapper} = T(obj) Base.convert(::Type{T}, obj::T) where {T<:FunctionWrapper} = obj @noinline function reinit_wrapper(f::FunctionWrapper{Ret,Args}) where {Ret,Args} - objref = f.obj + obj = f.obj objT = f.objT - ptr = make_cfunction(obj, Ret, Args) + cfun = make_cfunction(obj, Ret, Args) + ptr = Base.unsafe_convert(Ptr{Cvoid}, Base.cconvert(Ptr{Cvoid}, cfun)) f.ptr = ptr - f.objptr = Base.unsafe_convert(Ref{objT}, objref) + f.objptr = Base.unsafe_convert(Ref{objT}, Base.cconvert(Ref{objT}, obj)) + f.cfun = cfun return ptr end @@ -80,8 +100,8 @@ end assume(ptr != C_NULL) objptr = f.objptr ccall(ptr, $(map_rettype(Ret)), - (Ptr{Cvoid}, $((map_argtype(Arg) for Arg in Args.parameters)...)), - objptr, $((:(args[$i]) for i in 1:length(Args.parameters))...)) + ($((map_argtype(Arg) for Arg in Args.parameters)...),), + $((:(args[$i]) for i in 1:length(Args.parameters))...)) end end From 9d027e6d39986cf364db8401f8a693519e28648c Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Sat, 11 Aug 2018 17:11:35 -0400 Subject: [PATCH 5/6] CI updates. --- .travis.yml | 6 +++++- appveyor.yml | 42 +++++++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 34bfce9..746a026 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,10 @@ os: - osx julia: - 0.7 + - 1.0 - nightly +matrix: + allow_failures: + - julia: nightly after_success: - - julia -e 'cd(Pkg.dir("FunctionWrappers")); Pkg.add("Coverage"); using Coverage; Codecov.submit(process_folder())' + - julia --project -e 'import Pkg; Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())' diff --git a/appveyor.yml b/appveyor.yml index fb5a3a2..964272f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,13 +1,21 @@ environment: matrix: - - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.7/julia-0.7-latest-win32.exe" - - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.7/julia-0.7-latest-win64.exe" - - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe" - - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe" + - julia_version: 0.7 + - julia_version: 1 + - julia_version: nightly + +platform: + - x86 # 32-bit + - x64 # 64-bit + +matrix: + allow_failures: + - julia_version: latest branches: only: - master + - /release-.*/ notifications: - provider: Email @@ -16,22 +24,18 @@ notifications: on_build_status_changed: false install: - - ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12" -# if there's a newer build queued for the same PR, cancel this one - - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod ` - https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | ` - Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { ` - throw "There are newer queued builds for this pull request, failing early." } -# Download most recent Julia Windows binary - - ps: (new-object net.webclient).DownloadFile( - $env:JULIA_URL, - "C:\projects\julia-binary.exe") -# Run installer silently, output to C:\projects\julia - - C:\projects\julia-binary.exe /S /D=C:\projects\julia + - ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1")) build_script: - - C:\projects\julia\bin\julia -e "versioninfo(); - Pkg.clone(pwd(), \"FunctionWrappers\"); Pkg.build(\"FunctionWrappers\")" + - echo "%JL_BUILD_SCRIPT%" + - C:\julia\bin\julia -e "%JL_BUILD_SCRIPT%" test_script: - - C:\projects\julia\bin\julia --check-bounds=yes -e "Pkg.test(\"FunctionWrappers\")" + - echo "%JL_TEST_SCRIPT%" + - C:\julia\bin\julia -e "%JL_TEST_SCRIPT%" + +# # Uncomment to support code coverage upload. Should only be enabled for packages +# # which would have coverage gaps without running on Windows +# on_success: +# - echo "%JL_CODECOV_SCRIPT%" +# - C:\julia\bin\julia -e "%JL_CODECOV_SCRIPT%" From 395801f14c580cda467065ac8996678dd489c041 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Sat, 11 Aug 2018 17:20:02 -0400 Subject: [PATCH 6/6] Fix type instability due to reinit_wrapper. Down to zero allocs again. --- src/FunctionWrappers.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FunctionWrappers.jl b/src/FunctionWrappers.jl index 730af90..9e4d004 100644 --- a/src/FunctionWrappers.jl +++ b/src/FunctionWrappers.jl @@ -84,7 +84,7 @@ Base.convert(::Type{T}, obj::T) where {T<:FunctionWrapper} = obj f.ptr = ptr f.objptr = Base.unsafe_convert(Ref{objT}, Base.cconvert(Ref{objT}, obj)) f.cfun = cfun - return ptr + return ptr::Ptr{Cvoid} end @generated function do_ccall(f::FunctionWrapper{Ret,Args}, args::Args) where {Ret,Args}