diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index f394542877e12..1c12bbf0c5e64 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -3283,6 +3283,7 @@ function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecializ exct = Union{exct, ConcurrencyViolationError} end end + ⊑ = partialorder(typeinf_lattice(interp)) if M isa Const && s isa Const M, s = M.val, s.val if M isa Module && s isa Symbol diff --git a/Compiler/test/codegen.jl b/Compiler/test/codegen.jl index 4e0a1b1f88997..fd8bbae70a346 100644 --- a/Compiler/test/codegen.jl +++ b/Compiler/test/codegen.jl @@ -1027,3 +1027,8 @@ module TurnedIntoExplicit @test !occursin("jl_apply_generic", get_llvm(f, Tuple{UInt})) end + +# Test codegen for `isdefinedglobal` of constant (#57872) +const x57872 = "Hello" +f57872() = (Core.isdefinedglobal(@__MODULE__, Base.compilerbarrier(:const, :x57872)), x57872) # Extra globalref here to force world age bounds +@test f57872() == (true, "Hello") diff --git a/base/cmd.jl b/base/cmd.jl index b46c8293cdf3c..12d576e0e4c4b 100644 --- a/base/cmd.jl +++ b/base/cmd.jl @@ -504,7 +504,7 @@ julia> run(cm) Process(`echo 1`, ProcessExited(0)) ``` """ -macro cmd(str) +macro cmd(str::String) cmd_ex = shell_parse(str, special=shell_special, filename=String(__source__.file))[1] return :(cmd_gen($(esc(cmd_ex)))) end diff --git a/base/int.jl b/base/int.jl index 9bd4df6bd3866..24b7abc646281 100644 --- a/base/int.jl +++ b/base/int.jl @@ -286,8 +286,14 @@ function mod(x::T, y::T) where T<:Integer y == -1 && return T(0) # avoid potential overflow in fld return x - fld(x, y) * y end -mod(x::BitSigned, y::Unsigned) = rem(y + unsigned(rem(x, y)), y) -mod(x::Unsigned, y::Signed) = rem(y + signed(rem(x, y)), y) +function mod(x::BitSigned, y::Unsigned) + remval = rem(x, y) # correct iff remval>=0 + return unsigned(remval + (remval0 so correct iff y>0 or remval==0 + return remval + (!iszero(remval) && ydisabled, 1=>safe (static errors), 2=>unsafe, 3=>unsafe plus warnings) + If enabled emit LLVM IR for all functions even if wouldn't be compiled + for some reason (i.e functions that return a constant value). """ - trim::Cint + force_emit_all::Cint function CodegenParams(; track_allocations::Bool=true, code_coverage::Bool=true, prefer_specsig::Bool=false, gnu_pubnames::Bool=true, debug_info_kind::Cint = default_debug_info_kind(), debug_info_level::Cint = Cint(JLOptions().debug_level), safepoint_on_entry::Bool=true, - gcstack_arg::Bool=true, use_jlplt::Bool=true, trim::Cint=Cint(0)) + gcstack_arg::Bool=true, use_jlplt::Bool=true, force_emit_all::Bool=false) return new( Cint(track_allocations), Cint(code_coverage), Cint(prefer_specsig), Cint(gnu_pubnames), debug_info_kind, debug_info_level, Cint(safepoint_on_entry), - Cint(gcstack_arg), Cint(use_jlplt), Cint(trim)) + Cint(gcstack_arg), Cint(use_jlplt), Cint(force_emit_all)) end end diff --git a/base/strings/io.jl b/base/strings/io.jl index b4a3c7ad3e0c2..b27a6049f0b0e 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -589,7 +589,7 @@ julia> v[2] 0x32 ``` """ -macro b_str(s) +macro b_str(s::String) v = codeunits(unescape_string(s)) QuoteNode(v) end diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 9fab5b11d97c4..688aeca1b242c 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -775,7 +775,7 @@ void *jl_emit_native_impl(jl_array_t *codeinfos, LLVMOrcThreadSafeModuleRef llvm params.tsctx, clone.getModuleUnlocked()->getDataLayout(), Triple(clone.getModuleUnlocked()->getTargetTriple())); jl_llvm_functions_t decls; - if (jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr) + if (!(params.params->force_emit_all) && jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr) decls.functionObject = "jl_fptr_const_return"; else decls = jl_emit_codeinst(result_m, codeinst, src, params); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index bd6670c322ef6..9e70b2f3e6679 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -4410,7 +4410,8 @@ static int compare_cgparams(const jl_cgparams_t *a, const jl_cgparams_t *b) (a->debug_info_kind == b->debug_info_kind) && (a->safepoint_on_entry == b->safepoint_on_entry) && (a->gcstack_arg == b->gcstack_arg) && - (a->use_jlplt == b->use_jlplt); + (a->use_jlplt == b->use_jlplt) && + (a->force_emit_all == b->force_emit_all); } #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index e6c116f029f31..8c9f61d511a06 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3824,12 +3824,11 @@ static bool emit_f_opfield(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, static jl_cgval_t emit_isdefinedglobal(jl_codectx_t &ctx, jl_module_t *modu, jl_sym_t *name, int allow_import, enum jl_memory_order order) { - Value *isnull = NULL; jl_binding_t *bnd = allow_import ? jl_get_binding(modu, name) : jl_get_module_binding(modu, name, 0); struct restriction_kind_pair rkp = { NULL, NULL, PARTITION_KIND_GUARD, 0 }; if (allow_import && jl_get_binding_leaf_partitions_restriction_kind(bnd, &rkp, ctx.min_world, ctx.max_world)) { - if (jl_bkind_is_some_constant(rkp.kind)) - return mark_julia_const(ctx, rkp.restriction); + if (jl_bkind_is_some_constant(rkp.kind) && rkp.restriction) + return mark_julia_const(ctx, jl_true); if (rkp.kind == PARTITION_KIND_GLOBAL) { Value *bp = julia_binding_gv(ctx, rkp.binding_if_global); bp = julia_binding_pvalue(ctx, bp); @@ -3837,17 +3836,17 @@ static jl_cgval_t emit_isdefinedglobal(jl_codectx_t &ctx, jl_module_t *modu, jl_ jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_binding); ai.decorateInst(v); v->setOrdering(get_llvm_atomic_order(order)); - isnull = ctx.builder.CreateICmpNE(v, Constant::getNullValue(ctx.types().T_prjlvalue)); + Value *isnull = ctx.builder.CreateICmpNE(v, Constant::getNullValue(ctx.types().T_prjlvalue)); return mark_julia_type(ctx, isnull, false, jl_bool_type); } } - Value *v = ctx.builder.CreateCall(prepare_call(jlboundp_func), { + Value *isdef = ctx.builder.CreateCall(prepare_call(jlboundp_func), { literal_pointer_val(ctx, (jl_value_t*)modu), literal_pointer_val(ctx, (jl_value_t*)name), ConstantInt::get(getInt32Ty(ctx.builder.getContext()), allow_import) }); - isnull = ctx.builder.CreateICmpNE(v, ConstantInt::get(getInt32Ty(ctx.builder.getContext()), 0)); - return mark_julia_type(ctx, isnull, false, jl_bool_type); + isdef = ctx.builder.CreateTrunc(isdef, getInt1Ty(ctx.builder.getContext())); + return mark_julia_type(ctx, isdef, false, jl_bool_type); } static bool emit_f_opmemory(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, diff --git a/src/init.c b/src/init.c index 333c469226fcf..3ac4f8f7d770b 100644 --- a/src/init.c +++ b/src/init.c @@ -739,7 +739,8 @@ JL_DLLEXPORT jl_cgparams_t jl_default_cgparams = { /* debug_info_level */ 0, // later jl_options.debug_level, /* safepoint_on_entry */ 1, /* gcstack_arg */ 1, - /* use_jlplt*/ 1 }; + /* use_jlplt*/ 1 , + /*force_emit_all=*/ 0}; static void init_global_mutexes(void) { JL_MUTEX_INIT(&jl_modules_mutex, "jl_modules_mutex"); diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 8bc313610bbfa..739fa45e088ca 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -4657,9 +4657,9 @@ f(x) = yt(x) (let ((e1 (if (and arg-map (symbol? e)) (get arg-map e e) e))) - (if (and value (or (underscore-symbol? e) - (and (pair? e) (eq? (car e) 'globalref) - (underscore-symbol? (cadr e))))) + (if (or (underscore-symbol? e) + (and (pair? e) (eq? (car e) 'globalref) + (underscore-symbol? (cadr e)))) (error (string "all-underscore identifiers are write-only and their values cannot be used in expressions" (format-loc current-loc)))) (cond (tail (emit-return tail e1)) (value e1) diff --git a/src/julia.h b/src/julia.h index 30e4eb71f2320..56b61d2a04000 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2727,6 +2727,7 @@ typedef struct { int gcstack_arg; // Pass the ptls value as an argument with swiftself int use_jlplt; // Whether to use the Julia PLT mechanism or emit symbols directly + int force_emit_all; // Force emission of code for const return functions } jl_cgparams_t; extern JL_DLLEXPORT int jl_default_debug_info_kind; extern JL_DLLEXPORT jl_cgparams_t jl_default_cgparams; diff --git a/src/method.c b/src/method.c index 353fbdaf0ecff..abf039d9bce08 100644 --- a/src/method.c +++ b/src/method.c @@ -84,7 +84,8 @@ static jl_value_t *resolve_definition_effects(jl_value_t *expr, jl_module_t *mod int binding_effects, int eager_resolve) { if (jl_is_symbol(expr)) { - jl_error("Found raw symbol in code returned from lowering. Expected all symbols to have been resolved to GlobalRef or slots."); + jl_errorf("Found raw symbol %s in code returned from lowering. Expected all symbols to have been resolved to GlobalRef or slots.", + jl_symbol_name((jl_sym_t*)expr)); } if (!jl_is_expr(expr)) { diff --git a/src/signals-unix.c b/src/signals-unix.c index 1f4ad647a87af..2db397050420e 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -559,6 +559,7 @@ static int thread0_exit_signo = 0; static void JL_NORETURN jl_exit_thread0_cb(void) { CFI_NORETURN + jl_atomic_fetch_add(&jl_gc_disable_counter, -1); jl_critical_error(thread0_exit_signo, 0, NULL, jl_current_task); jl_atexit_hook(128); jl_raise(thread0_exit_signo); @@ -1089,6 +1090,10 @@ static void *signal_listener(void *arg) //#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L && !HAVE_KEVENT // si_code = info.si_code; //#endif + // Let's forbid threads from running GC while we're trying to exit, + // also let's make sure we're not in the middle of GC. + jl_atomic_fetch_add(&jl_gc_disable_counter, 1); + jl_safepoint_wait_gc(NULL); jl_exit_thread0(sig, signal_bt_data, signal_bt_size); } else if (critical) { diff --git a/src/toplevel.c b/src/toplevel.c index 73b65ecf2e3fb..174bb0ef4dd22 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -662,7 +662,7 @@ static void import_module(jl_task_t *ct, jl_module_t *JL_NONNULL m, jl_module_t if (!jl_bkind_is_some_implicit(kind) && kind != PARTITION_KIND_DECLARED) { // Unlike regular constant declaration, we allow this as long as we eventually end up at a constant. jl_walk_binding_inplace(&b, &bpart, ct->world_age); - if (jl_binding_kind(bpart) == PARTITION_KIND_CONST || jl_binding_kind(bpart) == PARTITION_KIND_BACKDATED_CONST || jl_binding_kind(bpart) == PARTITION_KIND_CONST_IMPORT) { + if (jl_bkind_is_some_constant(jl_binding_kind(bpart))) { // Already declared (e.g. on another thread) or imported. if (bpart->restriction == (jl_value_t*)import) return; diff --git a/stdlib/LibGit2/src/LibGit2.jl b/stdlib/LibGit2/src/LibGit2.jl index 04435dd577c19..4eed62331bdbc 100644 --- a/stdlib/LibGit2/src/LibGit2.jl +++ b/stdlib/LibGit2/src/LibGit2.jl @@ -1042,24 +1042,20 @@ function set_ssl_cert_locations(cert_loc) else # files, /dev/null, non-existent paths, etc. cert_file = cert_loc end - ret = @ccall libgit2.git_libgit2_opts( + ret = @ccall libgit2.git_libgit2_opts( Consts.SET_SSL_CERT_LOCATIONS::Cint; cert_file::Cstring, cert_dir::Cstring)::Cint ret >= 0 && return ret + # On macOS and Windows LibGit2_jll is built without a TLS backend that supports + # certificate locations; don't throw on this expected error so we allow certificate + # location environment variables to be set for other purposes. + # We still try doing so to support other LibGit2 builds. err = Error.GitError(ret) err.class == Error.SSL && err.msg == "TLS backend doesn't support certificate locations" || throw(err) - var = nothing - for v in NetworkOptions.CA_ROOTS_VARS - haskey(ENV, v) && (var = v) - end - @assert var !== nothing # otherwise we shouldn't be here - msg = """ - Your Julia is built with a SSL/TLS engine that libgit2 doesn't know how to configure to use a file or directory of certificate authority roots, but your environment specifies one via the $var variable. If you believe your system's root certificates are safe to use, you can `export JULIA_SSL_CA_ROOTS_PATH=""` in your environment to use those instead. - """ - throw(Error.GitError(err.class, err.code, chomp(msg))) + return ret end """ diff --git a/stdlib/LibGit2/test/bad_ca_roots.jl b/stdlib/LibGit2/test/bad_ca_roots.jl index 4882065167bdb..4caed4ed90beb 100644 --- a/stdlib/LibGit2/test/bad_ca_roots.jl +++ b/stdlib/LibGit2/test/bad_ca_roots.jl @@ -12,20 +12,24 @@ const CAN_SET_CA_ROOTS_PATH = !Sys.isapple() && !Sys.iswindows() # Given this is a sub-processed test file, not using @testsets avoids # leaking the report print into the Base test runner report begin # empty CA roots file - # these fail for different reasons on different platforms: - # - on Apple & Windows you cannot set the CA roots path location - # - on Linux & FreeBSD you you can but these are invalid files + # different behavior on different platforms: + # - on Apple & Windows you cannot set the CA roots path location; don't error + # - on Linux & FreeBSD you can but these are invalid files + ENV["JULIA_SSL_CA_ROOTS_PATH"] = "/dev/null" - @test_throws LibGit2.GitError LibGit2.ensure_initialized() + if CAN_SET_CA_ROOTS_PATH + @test_throws LibGit2.GitError LibGit2.ensure_initialized() + else + @test LibGit2.ensure_initialized() === nothing + end + ENV["JULIA_SSL_CA_ROOTS_PATH"] = tempname() - @test_throws LibGit2.GitError LibGit2.ensure_initialized() - # test that it still fails if called a second time - @test_throws LibGit2.GitError LibGit2.ensure_initialized() - if !CAN_SET_CA_ROOTS_PATH - # test that this doesn't work on macOS & Windows - ENV["JULIA_SSL_CA_ROOTS_PATH"] = NetworkOptions.bundled_ca_roots() + if CAN_SET_CA_ROOTS_PATH + @test_throws LibGit2.GitError LibGit2.ensure_initialized() + # test that it still fails if called a second time @test_throws LibGit2.GitError LibGit2.ensure_initialized() - delete!(ENV, "JULIA_SSL_CA_ROOTS_PATH") + else + @test LibGit2.ensure_initialized() === nothing @test LibGit2.ensure_initialized() === nothing end end diff --git a/stdlib/Profile/src/Allocs.jl b/stdlib/Profile/src/Allocs.jl index 9d0b18cb468ca..93c9d3392626f 100644 --- a/stdlib/Profile/src/Allocs.jl +++ b/stdlib/Profile/src/Allocs.jl @@ -79,11 +79,11 @@ end function _prof_expr(expr, opts) quote $start(; $(esc(opts))) - try + Base.@__tryfinally( $(esc(expr)) - finally + , $stop() - end + ) end end diff --git a/stdlib/Profile/src/Profile.jl b/stdlib/Profile/src/Profile.jl index 2e4092fb22c24..27f32fc453d55 100644 --- a/stdlib/Profile/src/Profile.jl +++ b/stdlib/Profile/src/Profile.jl @@ -56,12 +56,12 @@ appended to an internal buffer of backtraces. """ macro profile(ex) return quote - try - start_timer() + start_timer() + Base.@__tryfinally( $(esc(ex)) - finally + , stop_timer() - end + ) end end @@ -78,12 +78,12 @@ it can be used to diagnose performance issues such as lock contention, IO bottle """ macro profile_walltime(ex) return quote - try - start_timer(true) + start_timer(true); + Base.@__tryfinally( $(esc(ex)) - finally + , stop_timer() - end + ) end end diff --git a/stdlib/Profile/test/runtests.jl b/stdlib/Profile/test/runtests.jl index e7877b949a17e..b487d8963f156 100644 --- a/stdlib/Profile/test/runtests.jl +++ b/stdlib/Profile/test/runtests.jl @@ -155,6 +155,20 @@ end @test z == 10 end +@testset "@profile no scope" begin + @profile no_scope_57858_1 = 1 + @test @isdefined no_scope_57858_1 + Profile.clear() + + @profile_walltime no_scope_57858_1 = 1 + @test @isdefined no_scope_57858_1 + Profile.clear() + + Profile.Allocs.@profile no_scope_57858_2 = 1 + @test @isdefined no_scope_57858_2 + Profile.Allocs.clear() +end + @testset "setting sample count and delay in init" begin n_, delay_ = Profile.init() n_original = n_ diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index c621fbbb0836e..ae2fec4ee10e0 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -120,6 +120,22 @@ mutable struct REPLBackend end REPLBackend() = REPLBackend(Channel(1), Channel(1), false) +# A reference to a backend that is not mutable +struct REPLBackendRef + repl_channel::Channel{Any} + response_channel::Channel{Any} +end +REPLBackendRef(backend::REPLBackend) = REPLBackendRef(backend.repl_channel, backend.response_channel) + +function destroy(ref::REPLBackendRef, state::Task) + if istaskfailed(state) + close(ref.repl_channel, TaskFailedException(state)) + close(ref.response_channel, TaskFailedException(state)) + end + close(ref.repl_channel) + close(ref.response_channel) +end + """ softscope(ex) @@ -418,12 +434,23 @@ function repl_backend_loop(backend::REPLBackend, get_module::Function) while true tls = task_local_storage() tls[:SOURCE_PATH] = nothing - ast, show_value = take!(backend.repl_channel) + ast_or_func, show_value = take!(backend.repl_channel) if show_value == -1 # exit flag break end - eval_user_input(ast, backend, get_module()) + if show_value == 2 # 2 indicates a function to be called + f = ast_or_func + try + ret = f() + put!(backend.response_channel, Pair{Any, Bool}(ret, false)) + catch err + put!(backend.response_channel, Pair{Any, Bool}(err, true)) + end + else + ast = ast_or_func + eval_user_input(ast, backend, get_module()) + end end return nothing end @@ -526,7 +553,7 @@ function print_response(repl::AbstractREPL, response, show_value::Bool, have_col repl.waserror = response[2] with_repl_linfo(repl) do io io = IOContext(io, :module => Base.active_module(repl)::Module) - print_response(io, response, show_value, have_color, specialdisplay(repl)) + print_response(io, response, backend(repl), show_value, have_color, specialdisplay(repl)) end return nothing end @@ -543,7 +570,7 @@ function repl_display_error(errio::IO, @nospecialize errval) return nothing end -function print_response(errio::IO, response, show_value::Bool, have_color::Bool, specialdisplay::Union{AbstractDisplay,Nothing}=nothing) +function print_response(errio::IO, response, backend::Union{REPLBackendRef,Nothing}, show_value::Bool, have_color::Bool, specialdisplay::Union{AbstractDisplay,Nothing}=nothing) Base.sigatomic_begin() val, iserr = response while true @@ -555,15 +582,19 @@ function print_response(errio::IO, response, show_value::Bool, have_color::Bool, repl_display_error(errio, val) else if val !== nothing && show_value - try - if specialdisplay === nothing + val2, iserr = if specialdisplay === nothing + # display calls may require being run on the main thread + eval_with_backend(backend) do Base.invokelatest(display, val) - else + end + else + eval_with_backend(backend) do Base.invokelatest(display, specialdisplay, val) end - catch + end + if iserr println(errio, "Error showing value of type ", typeof(val), ":") - rethrow() + throw(val2) end end end @@ -593,21 +624,7 @@ function print_response(errio::IO, response, show_value::Bool, have_color::Bool, nothing end -# A reference to a backend that is not mutable -struct REPLBackendRef - repl_channel::Channel{Any} - response_channel::Channel{Any} -end -REPLBackendRef(backend::REPLBackend) = REPLBackendRef(backend.repl_channel, backend.response_channel) -function destroy(ref::REPLBackendRef, state::Task) - if istaskfailed(state) - close(ref.repl_channel, TaskFailedException(state)) - close(ref.response_channel, TaskFailedException(state)) - end - close(ref.repl_channel) - close(ref.response_channel) -end """ run_repl(repl::AbstractREPL) @@ -1128,12 +1145,27 @@ find_hist_file() = get(ENV, "JULIA_HISTORY", !isempty(DEPOT_PATH) ? joinpath(DEPOT_PATH[1], "logs", "repl_history.jl") : error("DEPOT_PATH is empty and ENV[\"JULIA_HISTORY\"] not set.")) -backend(r::AbstractREPL) = r.backendref +backend(r::AbstractREPL) = hasproperty(r, :backendref) ? r.backendref : nothing -function eval_with_backend(ast, backend::REPLBackendRef) - put!(backend.repl_channel, (ast, 1)) + +function eval_with_backend(ast::Expr, backend::REPLBackendRef) + put!(backend.repl_channel, (ast, 1)) # (f, show_value) + return take!(backend.response_channel) # (val, iserr) +end +function eval_with_backend(f, backend::REPLBackendRef) + put!(backend.repl_channel, (f, 2)) # (f, show_value) 2 indicates function (rather than ast) return take!(backend.response_channel) # (val, iserr) end +# if no backend just eval (used by tests) +function eval_with_backend(f, backend::Nothing) + try + ret = f() + return (ret, false) # (val, iserr) + catch err + return (err, true) + end +end + function respond(f, repl, main; pass_empty::Bool = false, suppress_on_semicolon::Bool = true) return function do_respond(s::MIState, buf, ok::Bool) diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index 241464ca48942..d1233ee00da1b 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -925,7 +925,7 @@ function test19864() @eval Base.showerror(io::IO, e::Error19864) = print(io, "correct19864") buf = IOBuffer() fake_response = (Base.ExceptionStack([(exception=Error19864(),backtrace=Ptr{Cvoid}[])]),true) - REPL.print_response(buf, fake_response, false, false, nothing) + REPL.print_response(buf, fake_response, nothing, false, false, nothing) return String(take!(buf)) end @test occursin("correct19864", test19864()) diff --git a/test/int.jl b/test/int.jl index dda736cd7a9d0..715625cf8b6d9 100644 --- a/test/int.jl +++ b/test/int.jl @@ -362,6 +362,23 @@ end end end end + # exhaustive UInt8/Int8 tests for mixed signedness + for f in (mod, rem) + for i in -128:127 + for j in 0:255 + if iszero(i) + @test_throws DivideError f(UInt8(j), Int8(i)) + else + @test f(UInt8(j), Int8(i)) == f(j, i) + end + if iszero(j) + @test_throws DivideError f(Int8(i), UInt8(j)) + else + @test f(Int8(i), UInt8(j)) == f(i,j) + end + end + end + end end @testset "Underscores in big_str" begin diff --git a/test/syntax.jl b/test/syntax.jl index 7e09f4747f939..b53a3b4357dc4 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -2827,6 +2827,20 @@ end @m38386 @test isempty(methods(f38386)) +@testset "non-lhs all-underscore vars should fail in lowering" begin + # OK + @test (_ = 1) === 1 + @test ((_, _) = (1, 2)) == (1, 2) + @test Meta.isexpr(Meta.lower(Main, :(for _ in 1:2; 1; end)), :thunk) + @test (try; throw(1); catch _; 2; end) === 2 + @test (let _ = 1; 2; end) === 2 + # ERROR: syntax: all-underscore identifiers are write-only and their values cannot be used in expressions + @test Meta.isexpr(Meta.lower(Main, :(_ = 1; a = _)), :error) + @test Meta.isexpr(Meta.lower(Main, :(let; function f(); _; end; end)), :error) + @test Meta.isexpr(Meta.lower(Main, :(let; function f(); _; 1; end; end)), :error) + @test Meta.isexpr(Meta.lower(Main, :(begin; _; 1; end)), :error) +end + @testset "all-underscore varargs on the rhs" begin @test ncalls_in_lowered(quote _..., = a end, GlobalRef(Base, :rest)) == 0 @test ncalls_in_lowered(quote ___..., = a end, GlobalRef(Base, :rest)) == 0 @@ -4236,3 +4250,10 @@ out = let end end @test M57574.out === M57574.A + +# Double import of CONST_IMPORT symbol +module DoubleImport + import Test: Random + import Random +end +@test DoubleImport.Random === Test.Random