diff --git a/base/c.jl b/base/c.jl index fdcc405b3146d..5b7f6bb0efa7d 100644 --- a/base/c.jl +++ b/base/c.jl @@ -639,7 +639,7 @@ function ccall_macro_parse(expr::Expr) end -function ccall_macro_lower(convention, func, rettype, types, args, nreq) +function ccall_macro_lower(convention, effects, func, rettype, types, args, nreq) lowering = [] realargs = [] gcroots = [] @@ -676,7 +676,7 @@ function ccall_macro_lower(convention, func, rettype, types, args, nreq) esc(etypes), nreq, QuoteNode(convention), - nothing, + effects, realargs..., gcroots...) push!(lowering, exp) @@ -732,5 +732,9 @@ The string literal could also be used directly before the function name, if desired `"libglib-2.0".g_uri_escape_string(...` """ macro ccall(expr) - return ccall_macro_lower(:ccall, ccall_macro_parse(expr)...) + return ccall_macro_lower(:ccall, nothing, ccall_macro_parse(expr)...) +end + +macro ccall_effects(effects, expr) + return ccall_macro_lower(:ccall, effects, ccall_macro_parse(expr)...) end diff --git a/base/compiler/types.jl b/base/compiler/types.jl index fffe23b687d92..50a387bc2d080 100644 --- a/base/compiler/types.jl +++ b/base/compiler/types.jl @@ -68,9 +68,9 @@ function encode_effects_override(eo::EffectsOverride) e = 0x00 eo.consistent && (e |= 0x01) eo.effect_free && (e |= 0x02) - eo.nothrow && (e |= 0x02) - eo.terminates && (e |= 0x04) - eo.terminates_locally && (e |= 0x08) + eo.nothrow && (e |= 0x04) + eo.terminates && (e |= 0x08) + eo.terminates_locally && (e |= 0x10) e end @@ -82,7 +82,6 @@ decode_effects_override(e::UInt8) = (e >> 3) & 0x01 != 0x00, (e >> 4) & 0x01 != 0x00) - """ InferenceResult diff --git a/base/expr.jl b/base/expr.jl index f3a694960aa3e..dfd36f3e877e3 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -520,7 +520,14 @@ macro assume_effects(args...) end end ex = args[end] - isa(ex, Expr) || ArgumentError("Bad expression `$ex` in @constprop [settings] ex") + isa(ex, Expr) || throw(ArgumentError("Bad expression `$ex` in @constprop [settings] ex")) + if ex.head === :macrocall && ex.args[1] == Symbol("@ccall") + ex.args[1] = GlobalRef(Base, Symbol("@ccall_effects")) + insert!(ex.args, 3, Core.Compiler.encode_effects_override(Core.Compiler.EffectsOverride( + consistent, effect_free, nothrow, terminates_globally, terminates_locally + ))) + return esc(ex) + end return pushmeta!(ex, :purity, consistent, effect_free, nothrow, terminates_globally, terminates_locally) end diff --git a/test/ccall.jl b/test/ccall.jl index 55942d8310d82..f2ac071557de4 100644 --- a/test/ccall.jl +++ b/test/ccall.jl @@ -36,7 +36,7 @@ end Core.svec(Ptr{Ptr{Cchar}}, Cstring, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, Cfloat, Cfloat, Cfloat, Cfloat, Cfloat, Cfloat, Cfloat, Cfloat, Cfloat), - 2, :(:cdecl), + 2, :(:cdecl), nothing, :(Base.unsafe_convert(Ptr{Ptr{Cchar}}, strp)), :(Base.unsafe_convert(Cstring, fmt)), 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, Cfloat(1.1), Cfloat(2.2), Cfloat(3.3), Cfloat(4.4), Cfloat(5.5), Cfloat(6.6), Cfloat(7.7), Cfloat(8.8), Cfloat(9.9), @@ -1676,7 +1676,7 @@ using Base: ccall_macro_parse, ccall_macro_lower end @testset "ensure the base-case of @ccall works, including library name and pointer interpolation" begin - call = ccall_macro_lower(:ccall, ccall_macro_parse( :( libstring.func( + call = ccall_macro_lower(:ccall, nothing, ccall_macro_parse( :( libstring.func( str::Cstring, num1::Cint, num2::Cint @@ -1700,7 +1700,7 @@ end end) # pointer interpolation - call = ccall_macro_lower(:ccall, ccall_macro_parse(:( $(Expr(:$, :fptr))("bar"::Cstring)::Cvoid ))...) + call = ccall_macro_lower(:ccall, nothing, ccall_macro_parse(:( $(Expr(:$, :fptr))("bar"::Cstring)::Cvoid ))...) @test Base.remove_linenums!(call) == Base.remove_linenums!( quote func = $(Expr(:escape, :fptr)) @@ -1852,3 +1852,9 @@ end @test cglobal33413_literal() != C_NULL @test cglobal33413_literal_notype() != C_NULL end + +@testset "ccall_effects" begin + ctest_total(x) = @Base.assume_effects :total @ccall libccalltest.ctest(x::Complex{Int})::Complex{Int} + ctest_total_const() = Val{ctest_total(1 + 2im)}() + Core.Compiler.return_type(ctest_total_const, Tuple{}) == Val{2 + 0im} +end