diff --git a/base/Enums.jl b/base/Enums.jl index b4c02327dd5e2..f8574ad941dbe 100644 --- a/base/Enums.jl +++ b/base/Enums.jl @@ -47,13 +47,17 @@ function Base.show(io::IO, ::MIME"text/plain", x::Enum) show(io, Integer(x)) end -function Base.show(io::IO, ::MIME"text/plain", t::Type{<:Enum}) - print(io, "Enum ") - Base.show_datatype(io, t) - print(io, ":") - for x in instances(t) - print(io, "\n", Symbol(x), " = ") - show(io, Integer(x)) +function Base.show(io::IO, m::MIME"text/plain", t::Type{<:Enum}) + if isconcretetype(t) + print(io, "Enum ") + Base.show_datatype(io, t) + print(io, ":") + for x in instances(t) + print(io, "\n", Symbol(x), " = ") + show(io, Integer(x)) + end + else + invoke(show, Tuple{IO, MIME"text/plain", Type}, io, m, t) end end diff --git a/base/abstractarray.jl b/base/abstractarray.jl index c215b8f8aad7a..76675dc76e9a2 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1010,8 +1010,8 @@ function pointer(x::AbstractArray{T}, i::Integer) where T end # The distance from pointer(x) to the element at x[I...] in bytes -_memory_offset(x::DenseArray, I...) = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x) -function _memory_offset(x::AbstractArray, I...) +_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x) +function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N} J = _to_subscript_indices(x, I...) return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x) end diff --git a/base/compiler/inferencestate.jl b/base/compiler/inferencestate.jl index c6ac979abf96d..8ac40f2498dad 100644 --- a/base/compiler/inferencestate.jl +++ b/base/compiler/inferencestate.jl @@ -205,7 +205,10 @@ update_valid_age!(edge::InferenceState, sv::InferenceState) = update_valid_age!( function record_ssa_assign(ssa_id::Int, @nospecialize(new), frame::InferenceState) old = frame.src.ssavaluetypes[ssa_id] if old === NOT_FOUND || !(new ⊑ old) - frame.src.ssavaluetypes[ssa_id] = tmerge(old, new) + # typically, we expect that old ⊑ new (that output information only + # gets less precise with worse input information), but to actually + # guarantee convergence we need to use tmerge here to ensure that is true + frame.src.ssavaluetypes[ssa_id] = old === NOT_FOUND ? new : tmerge(old, new) W = frame.ip s = frame.stmt_types for r in frame.ssavalue_uses[ssa_id] diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 579727af41401..15fb81e6643ed 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -729,6 +729,9 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name)) end if isa(name, Const) nv = name.val + if !(isa(nv,Symbol) || isa(nv,Int)) + return Bottom + end if isa(sv, UnionAll) if nv === :var || nv === 1 return Const(sv.var) @@ -755,9 +758,6 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name)) if isa(sv, Module) && isa(nv, Symbol) return abstract_eval_global(sv, nv) end - if !(isa(nv,Symbol) || isa(nv,Int)) - return Bottom - end if (isa(sv, SimpleVector) || !ismutable(sv)) && isdefined(sv, nv) return AbstractEvalConstant(getfield(sv, nv)) end diff --git a/base/compiler/typelimits.jl b/base/compiler/typelimits.jl index 6a75835998970..cd88ac00180f4 100644 --- a/base/compiler/typelimits.jl +++ b/base/compiler/typelimits.jl @@ -283,6 +283,8 @@ end # but without losing too much precision in common cases # and also trying to be mostly associative and commutative function tmerge(@nospecialize(typea), @nospecialize(typeb)) + typea === Union{} && return typeb + typeb === Union{} && return typea suba = typea ⊑ typeb suba && issimpleenoughtype(typeb) && return typeb subb = typeb ⊑ typea diff --git a/base/deprecated.jl b/base/deprecated.jl index 5f083863ddc98..aa946cf02b443 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -76,12 +76,12 @@ macro deprecate(old, new, ex=true) end end -function depwarn(msg, funcsym) +function depwarn(msg, funcsym; force::Bool=false) opts = JLOptions() if opts.depwarn == 2 throw(ErrorException(msg)) end - deplevel = opts.depwarn == 1 ? CoreLogging.Warn : CoreLogging.BelowMinLevel + deplevel = force || opts.depwarn == 1 ? CoreLogging.Warn : CoreLogging.BelowMinLevel @logmsg( deplevel, msg, diff --git a/base/gcutils.jl b/base/gcutils.jl index 23ba4a82b65b5..5d6d8fc2c5805 100644 --- a/base/gcutils.jl +++ b/base/gcutils.jl @@ -132,9 +132,9 @@ directly to `ccall` which counts as an explicit use.) julia> let x = "Hello" p = pointer(x) - GC.@preserve x @ccall strlen(p::Cstring)::Cint + Int(GC.@preserve x @ccall strlen(p::Cstring)::Csize_t) # Preferred alternative - @ccall strlen(x::Cstring)::Cint + Int(@ccall strlen(x::Cstring)::Csize_t) end 5 ``` diff --git a/base/reflection.jl b/base/reflection.jl index bc72bbd11d311..08c243e64534e 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -433,6 +433,9 @@ false julia> ismutable([1,2]) true ``` + +!!! compat "Julia 1.5" + This function requires at least Julia 1.5. """ ismutable(@nospecialize(x)) = (@_pure_meta; typeof(x).mutable) diff --git a/base/secretbuffer.jl b/base/secretbuffer.jl index dae5a697a5bd7..02a133be088f0 100644 --- a/base/secretbuffer.jl +++ b/base/secretbuffer.jl @@ -79,7 +79,7 @@ function SecretBuffer!(d::Vector{UInt8}) s end -unsafe_SecretBuffer!(s::Cstring) = unsafe_SecretBuffer!(convert(Ptr{UInt8}, s), ccall(:strlen, Cint, (Cstring,), s)) +unsafe_SecretBuffer!(s::Cstring) = unsafe_SecretBuffer!(convert(Ptr{UInt8}, s), Int(ccall(:strlen, Csize_t, (Cstring,), s))) function unsafe_SecretBuffer!(p::Ptr{UInt8}, len=1) s = SecretBuffer(sizehint=len) for i in 1:len diff --git a/base/show.jl b/base/show.jl index a8bad7be8742e..12e7453a7a041 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1339,7 +1339,10 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int, quote_level::In # scalar multiplication (i.e. "100x") elseif (func === :* && length(func_args) == 2 && isa(func_args[1], Union{Int, Int64, Float32, Float64}) && - isa(func_args[2], Symbol) && !in(string(func_args[2])[1], ('e', 'E', 'f'))) + isa(func_args[2], Symbol) && + !in(string(func_args[2]::Symbol)[1], ('e', 'E', 'f', (func_args[1] == 0 && func_args[1] isa Integer ? + # don't juxtapose 0 with b, o, x + ('b', 'o', 'x') : ())...))) if func_prec <= prec show_enclosed_list(io, '(', func_args, "", ')', indent, func_prec, quote_level) else diff --git a/base/subarray.jl b/base/subarray.jl index 6e62d08b258e1..3fbb1a93570b5 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -366,17 +366,20 @@ end # The running sum is `f`; the cumulative stride product is `s`. # If the parent is a vector, then we offset the parent's own indices with parameters of I compute_offset1(parent::AbstractVector, stride1::Integer, I::Tuple{AbstractRange}) = - (@_inline_meta; first(I[1]) - first(axes1(I[1]))*stride1) + (@_inline_meta; first(I[1]) - stride1*first(axes1(I[1]))) # If the result is one-dimensional and it's a Colon, then linear -# indexing uses the indices along the given dimension. Otherwise -# linear indexing always starts with 1. +# indexing uses the indices along the given dimension. +# If the result is one-dimensional and it's a range, then linear +# indexing might be offset if the index itself is offset +# Otherwise linear indexing always starts with 1. compute_offset1(parent, stride1::Integer, I::Tuple) = (@_inline_meta; compute_offset1(parent, stride1, find_extended_dims(1, I...), find_extended_inds(I...), I)) -compute_offset1(parent, stride1::Integer, dims::Tuple{Int}, inds::Tuple{Union{Slice, IdentityUnitRange}}, I::Tuple) = +compute_offset1(parent, stride1::Integer, dims::Tuple{Int}, inds::Tuple{Slice}, I::Tuple) = (@_inline_meta; compute_linindex(parent, I) - stride1*first(axes(parent, dims[1]))) # index-preserving case +compute_offset1(parent, stride1::Integer, dims, inds::Tuple{AbstractRange}, I::Tuple) = + (@_inline_meta; compute_linindex(parent, I) - stride1*first(axes1(inds[1]))) # potentially index-offsetting case compute_offset1(parent, stride1::Integer, dims, inds, I::Tuple) = (@_inline_meta; compute_linindex(parent, I) - stride1) # linear indexing starts with 1 - function compute_linindex(parent, I::NTuple{N,Any}) where N @_inline_meta IP = fill_to_length(axes(parent), OneTo(1), Val(N)) diff --git a/base/traits.jl b/base/traits.jl index 3c6a8019483b7..69be1c947561e 100644 --- a/base/traits.jl +++ b/base/traits.jl @@ -9,6 +9,7 @@ struct Unordered <: OrderStyle end OrderStyle(instance) = OrderStyle(typeof(instance)) OrderStyle(::Type{<:Real}) = Ordered() OrderStyle(::Type{<:Any}) = Unordered() +OrderStyle(::Type{Union{}}) = Ordered() # trait for objects that support arithmetic abstract type ArithmeticStyle end diff --git a/deps/checksums/Pkg-1542f285243b8ac31e666dee3c6690bdaf26a0be.tar.gz/md5 b/deps/checksums/Pkg-1542f285243b8ac31e666dee3c6690bdaf26a0be.tar.gz/md5 new file mode 100644 index 0000000000000..3bb05eee69c88 --- /dev/null +++ b/deps/checksums/Pkg-1542f285243b8ac31e666dee3c6690bdaf26a0be.tar.gz/md5 @@ -0,0 +1 @@ +14d2db2253d6a561d7bf1cf66d0d3421 diff --git a/deps/checksums/Pkg-1542f285243b8ac31e666dee3c6690bdaf26a0be.tar.gz/sha512 b/deps/checksums/Pkg-1542f285243b8ac31e666dee3c6690bdaf26a0be.tar.gz/sha512 new file mode 100644 index 0000000000000..fa860ae53e3e0 --- /dev/null +++ b/deps/checksums/Pkg-1542f285243b8ac31e666dee3c6690bdaf26a0be.tar.gz/sha512 @@ -0,0 +1 @@ +da49f34f57e61f86e2124440676d44678a43a98fc96970debcd9ded931be3329acbadea858cc4100204ff1ecd7027b033f759a0c2595dcad6d6f114aadb3507d diff --git a/deps/checksums/Pkg-aaf4e6e8ab784f7435c1bdc56832bc03e014dedb.tar.gz/md5 b/deps/checksums/Pkg-aaf4e6e8ab784f7435c1bdc56832bc03e014dedb.tar.gz/md5 deleted file mode 100644 index 3fda5aaa8e39d..0000000000000 --- a/deps/checksums/Pkg-aaf4e6e8ab784f7435c1bdc56832bc03e014dedb.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -1ed38a16fc0a687878187d9d500a21e1 diff --git a/deps/checksums/Pkg-aaf4e6e8ab784f7435c1bdc56832bc03e014dedb.tar.gz/sha512 b/deps/checksums/Pkg-aaf4e6e8ab784f7435c1bdc56832bc03e014dedb.tar.gz/sha512 deleted file mode 100644 index 8b382f16b42ce..0000000000000 --- a/deps/checksums/Pkg-aaf4e6e8ab784f7435c1bdc56832bc03e014dedb.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -35cef24bdffc9572a54769585977661f2bc01baa67e98c7760cf59c81a25f46d9b7371463eb8f0a24ec6272888c786d7087a94b96952b352018d4e5f191d8267 diff --git a/doc/make.jl b/doc/make.jl index 391eb21c571c4..1dc60ec7ee543 100644 --- a/doc/make.jl +++ b/doc/make.jl @@ -1,4 +1,5 @@ # Install dependencies needed to build the documentation. +Base.HOME_PROJECT[] = nothing empty!(LOAD_PATH) push!(LOAD_PATH, @__DIR__, "@stdlib") empty!(DEPOT_PATH) diff --git a/src/Makefile b/src/Makefile index 0eaa214e5d074..ac2dbb456c98d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -373,6 +373,8 @@ ifneq ($(BUILD_LLVM_CLANG),1) endif endif +clangsa: $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) + clang-sa-%: $(SRCDIR)/%.c $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) | analyzegc-deps-check @$(call PRINT_ANALYZE, $(build_depsbindir)/clang --analyze -Xanalyzer -analyzer-werror -Xanalyzer -analyzer-output=text -Xclang -load -Xclang $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) $(CLANGSA_FLAGS) $(JCPPFLAGS) $(JCFLAGS) $(DEBUGFLAGS) -Xclang -analyzer-checker=core$(COMMA)julia.GCChecker --analyzer-no-default-checks -fcolor-diagnostics -Werror -x c $<) clang-sa-%: $(SRCDIR)/%.cpp $(build_shlibdir)/libGCCheckerPlugin.$(SHLIB_EXT) | analyzegc-deps-check diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 03b90640ee71a..30fe76cd5e03e 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -307,9 +307,11 @@ void *jl_create_native(jl_array_t *methods, const jl_cgparams_t cgparams, int _p } if (src == NULL || !jl_is_code_info(src)) { src = jl_type_infer(mi, params.world, 0); - codeinst = jl_get_method_inferred(mi, src->rettype, src->min_world, src->max_world); - if (src->inferred && !codeinst->inferred) - codeinst->inferred = jl_nothing; + if (src) { + codeinst = jl_get_method_inferred(mi, src->rettype, src->min_world, src->max_world); + if (src->inferred && !codeinst->inferred) + codeinst->inferred = jl_nothing; + } } if (src && !emitted.count(codeinst)) { // now add it to our compilation results diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 8cdaf9c5bd2f4..099a0b433b78b 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1682,16 +1682,18 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx, else if (is_tupletype_homogeneous(stt->types)) { assert(nfields > 0); // nf == 0 trapped by all_pointers case jl_value_t *jft = jl_svecref(stt->types, 0); + assert(jl_is_concrete_type(jft)); idx = idx0(); Value *ptr = maybe_decay_tracked(data_pointer(ctx, strct)); - if (!stt->mutabl && !(maybe_null && jft == (jl_value_t*)jl_bool_type)) { + if (!stt->mutabl && !(maybe_null && (jft == (jl_value_t*)jl_bool_type || + ((jl_datatype_t*)jft)->layout->npointers))) { // just compute the pointer and let user load it when necessary Type *fty = julia_type_to_llvm(ctx, jft); Value *addr = ctx.builder.CreateInBoundsGEP(fty, emit_bitcast(ctx, ptr, PointerType::get(fty, 0)), idx); *ret = mark_julia_slot(addr, jft, NULL, strct.tbaa); return true; } - *ret = typed_load(ctx, ptr, idx, jft, strct.tbaa, nullptr, false); + *ret = typed_load(ctx, ptr, idx, jft, strct.tbaa, nullptr, maybe_null); return true; } else if (strct.isboxed) { @@ -1779,12 +1781,14 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st } return mark_julia_slot(addr, jfty, tindex, strct.tbaa); } - else if (!jt->mutabl && !(maybe_null && jfty == (jl_value_t*)jl_bool_type)) { + assert(jl_is_concrete_type(jfty)); + if (!jt->mutabl && !(maybe_null && (jfty == (jl_value_t*)jl_bool_type || + ((jl_datatype_t*)jfty)->layout->npointers))) { // just compute the pointer and let user load it when necessary return mark_julia_slot(addr, jfty, NULL, strct.tbaa); } unsigned align = jl_field_align(jt, idx); - return typed_load(ctx, addr, NULL, jfty, strct.tbaa, nullptr, true, align); + return typed_load(ctx, addr, NULL, jfty, strct.tbaa, nullptr, maybe_null, align); } else if (isa(strct.V)) { return jl_cgval_t(); diff --git a/src/codegen.cpp b/src/codegen.cpp index a0af0a7f05e29..3427fdfd352fc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3355,7 +3355,7 @@ static void emit_ssaval_assign(jl_codectx_t &ctx, ssize_t idx, jl_value_t *r) static void emit_varinfo_assign(jl_codectx_t &ctx, jl_varinfo_t &vi, jl_cgval_t rval_info, jl_value_t *l=NULL) { - if (!vi.used) + if (!vi.used || vi.value.typ == jl_bottom_type) return; // convert rval-type to lval-type @@ -3441,6 +3441,49 @@ static void emit_assignment(jl_codectx_t &ctx, jl_value_t *l, jl_value_t *r, ssi emit_varinfo_assign(ctx, vi, rval_info, l); } +static void emit_upsilonnode(jl_codectx_t &ctx, ssize_t phic, jl_value_t *val) +{ + jl_varinfo_t &vi = ctx.phic_slots[phic]; + // If the val is null, we can ignore the store. + // The middle end guarantees that the value from this + // upsilon node is not dynamically observed. + if (val) { + jl_cgval_t rval_info = emit_expr(ctx, val); + if (rval_info.typ == jl_bottom_type) + // as a special case, PhiC nodes are allowed to use undefined + // values, since they are just copy operations, so we need to + // ignore the store (it will not by dynamically observed), while + // normally, for any other operation result, we'd assume this store + // was unreachable and dead + val = NULL; + else + emit_varinfo_assign(ctx, vi, rval_info); + } + if (!val) { + if (vi.boxroot) { + // memory optimization: eagerly clear this gc-root now + ctx.builder.CreateAlignedStore(ConstantPointerNull::get(cast(T_prjlvalue)), vi.boxroot, Align(sizeof(void*)), true); + } + if (vi.pTIndex) { + // We don't care what the contents of the variable are, but it + // does need to satisfy the union invariants (i.e. inbounds + // tindex). + ctx.builder.CreateAlignedStore( + vi.boxroot ? ConstantInt::get(T_int8, 0x80) : + ConstantInt::get(T_int8, 0x01), + vi.pTIndex, Align(1), true); + } + else if (vi.value.V && !vi.value.constant && vi.value.typ != jl_bottom_type) { + assert(vi.value.ispointer()); + Type *T = cast(vi.value.V)->getAllocatedType(); + if (CountTrackedPointers(T).count) { + // make sure gc pointers (including ptr_phi of union-split) are initialized to NULL + ctx.builder.CreateStore(Constant::getNullValue(T), vi.value.V, true); + } + } + } +} + // --- convert expression to code --- static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, const jl_cgval_t &fexpr, jl_value_t *rt, jl_svec_t *argt); @@ -5425,9 +5468,7 @@ static std::pair, jl_llvm_functions_t> i == 0) { // or it is the first argument (which isn't in `argArray`) AllocaInst *av = new AllocaInst(T_prjlvalue, 0, jl_symbol_name(s), /*InsertBefore*/ctx.ptlsStates); - StoreInst *SI = new StoreInst( - ConstantPointerNull::get(cast(T_prjlvalue)), av, - false); + StoreInst *SI = new StoreInst(ConstantPointerNull::get(cast(T_prjlvalue)), av, false, Align(sizeof(void*))); SI->insertAfter(ctx.ptlsStates); varinfo.boxroot = av; if (ctx.debug_enabled && varinfo.dinfo) { @@ -6020,23 +6061,7 @@ static std::pair, jl_llvm_functions_t> continue; } if (jl_is_upsilonnode(stmt)) { - jl_value_t *val = jl_fieldref_noalloc(stmt, 0); - // If the val is null, we can ignore the store. - // The middle end guarantees that the value from this - // upsilon node is not dynamically observed. - jl_varinfo_t &vi = ctx.phic_slots[upsilon_to_phic[cursor+1]]; - if (val) { - jl_cgval_t rval_info = emit_expr(ctx, val); - emit_varinfo_assign(ctx, vi, rval_info); - } else if (vi.pTIndex) { - // We don't care what the contents of the variable are, but it - // does need to satisfy the union invariants (i.e. inbounds - // tindex). - ctx.builder.CreateStore( - vi.boxroot ? ConstantInt::get(T_int8, 0x80) : - ConstantInt::get(T_int8, 0x01), - vi.pTIndex, true); - } + emit_upsilonnode(ctx, upsilon_to_phic[cursor + 1], jl_fieldref_noalloc(stmt, 0)); find_next_stmt(cursor + 1); continue; } @@ -6206,19 +6231,25 @@ static std::pair, jl_llvm_functions_t> } else { Value *RTindex; - Value *V; + // The branch below is a bit too complex for GCC to realize that + // `V` is always initialized when it is used. + // Ref https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96629 + Value *V = nullptr; if (val.typ == (jl_value_t*)jl_bottom_type) { - V = undef_value_for_type(VN->getType()); + if (VN) + V = undef_value_for_type(VN->getType()); RTindex = UndefValue::get(T_int8); } else if (jl_is_concrete_type(val.typ) || val.constant) { size_t tindex = get_box_tindex((jl_datatype_t*)val.typ, phiType); if (tindex == 0) { - V = boxed(ctx, val); + if (VN) + V = boxed(ctx, val); RTindex = ConstantInt::get(T_int8, 0x80); } else { - V = ConstantPointerNull::get(cast(T_prjlvalue)); + if (VN) + V = ConstantPointerNull::get(cast(T_prjlvalue)); Type *lty = julia_type_to_llvm(ctx, val.typ); if (dest && !type_is_ghost(lty)) // basically, if !ghost union emit_unbox(ctx, lty, val, val.typ, dest); @@ -6238,7 +6269,8 @@ static std::pair, jl_llvm_functions_t> } new_union.TIndex = RTindex; } - V = new_union.Vboxed ? new_union.Vboxed : ConstantPointerNull::get(cast(T_prjlvalue)); + if (VN) + V = new_union.Vboxed ? new_union.Vboxed : ConstantPointerNull::get(cast(T_prjlvalue)); if (dest) { // basically, if !ghost union Value *skip = NULL; if (new_union.Vboxed != nullptr) @@ -7230,7 +7262,6 @@ static void init_julia_llvm_env(Module *m) jl_newbits_func = Function::Create(FunctionType::get(T_prjlvalue, newbits_args, false), Function::ExternalLinkage, "jl_new_bits"); - add_return_attr(jl_newbits_func, Attribute::NoAlias); add_return_attr(jl_newbits_func, Attribute::NonNull); add_named_global(jl_newbits_func, (void*)jl_new_bits); diff --git a/src/jltypes.c b/src/jltypes.c index 2017ffd90f3e4..4b14f4a4b26ee 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -494,6 +494,7 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n) if (j != i && temp[i] && temp[j]) { if (temp[i] == temp[j] || temp[i] == jl_bottom_type || temp[j] == (jl_value_t*)jl_any_type || + jl_egal(temp[i], temp[j]) || (!has_free && !jl_has_free_typevars(temp[j]) && jl_subtype(temp[i], temp[j]))) { temp[i] = NULL; diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 10672095b5b64..06a0a5e066b6a 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -2034,6 +2034,7 @@ (n (length lhss)) (st (gensy))) `(block + (local ,st) ,@ini ,.(map (lambda (i lhs) (expand-forms diff --git a/src/macroexpand.scm b/src/macroexpand.scm index 0777c9c61846e..e6c4fde732611 100644 --- a/src/macroexpand.scm +++ b/src/macroexpand.scm @@ -280,6 +280,14 @@ (cdr e)))) (else (other e)))) +;; given the LHS of e.g. `x::Int -> y`, wrap the signature in `tuple` to normalize +(define (tuple-wrap-arrow-sig e) + (cond ((atom? e) `(tuple ,e)) + ((eq? (car e) 'where) `(where ,(tuple-wrap-arrow-arglist (cadr e)) ,@(cddr e))) + ((eq? (car e) 'tuple) e) + ((eq? (car e) 'escape) `(escape ,(tuple-wrap-arrow-sig (cadr e)))) + (else `(tuple ,e)))) + (define (new-expansion-env-for x env (outermost #f)) (let ((introduced (pattern-expand1 vars-introduced-by-patterns x))) (if (or (atom? x) @@ -370,7 +378,11 @@ (resolve-expansion-vars- x env m parent-scope #f))) (cdr e)))) - ((= function ->) + ((->) + `(-> ,(resolve-in-function-lhs (tuple-wrap-arrow-sig (cadr e)) env m parent-scope inarg) + ,(resolve-expansion-vars-with-new-env (caddr e) env m parent-scope inarg))) + + ((= function) (if (and (pair? (cadr e)) (function-def? e)) ;; in (kw x 1) inside an arglist, the x isn't actually a kwarg `(,(car e) ,(resolve-in-function-lhs (cadr e) env m parent-scope inarg) diff --git a/src/subtype.c b/src/subtype.c index 4aadeef340440..260252fe3d2dd 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -235,6 +235,10 @@ static int obviously_unequal(jl_value_t *a, jl_value_t *b) if (jl_is_datatype(b)) { jl_datatype_t *ad = (jl_datatype_t*)a; jl_datatype_t *bd = (jl_datatype_t*)b; + if (a == (jl_value_t*)jl_typeofbottom_type && bd->name == jl_type_typename) + return obviously_unequal(jl_bottom_type, jl_tparam(bd, 0)); + if (ad->name == jl_type_typename && b == (jl_value_t*)jl_typeofbottom_type) + return obviously_unequal(jl_tparam(ad, 0), jl_bottom_type); if (ad->name != bd->name) return 1; int istuple = (ad->name == jl_tuple_typename); diff --git a/stdlib/Markdown/src/Julia/interp.jl b/stdlib/Markdown/src/Julia/interp.jl index 50e51f0f90696..15afedb54868c 100644 --- a/stdlib/Markdown/src/Julia/interp.jl +++ b/stdlib/Markdown/src/Julia/interp.jl @@ -11,9 +11,13 @@ function interpinner(stream::IO, greedy = false) startswith(stream, '$') || return (eof(stream) || peek(stream, Char) in whitespace) && return try - return _parse(stream::IOBuffer, greedy = greedy) + return _parse(stream, greedy = greedy) catch e - return + if isa(e, Meta.ParseError) + return nothing + else + rethrow() + end end end @@ -39,10 +43,19 @@ end toexpr(x) = x -toexpr(xs::Vector{Any}) = Expr(:call, GlobalRef(Base,:getindex), Any, map(toexpr, xs)...) +toexpr(xs::Union{Vector{Any},Vector{Vector{Any}}}) = + Expr(:call, GlobalRef(Base,:getindex), Any, map(toexpr, xs)...) for T in Any[MD, Paragraph, Header, Link, Bold, Italic] @eval function toexpr(md::$T) Expr(:call, typeof(md), $(map(x->:(toexpr(md.$x)), fieldnames(Base.unwrap_unionall(T)))...)) end end + +function toexpr(md::Table) + Expr(:call, Table, toexpr(md.rows), md.align) +end + +function toexpr(md::List) + Expr(:call, List, toexpr(md.items), md.ordered, md.loose) +end diff --git a/stdlib/Markdown/test/runtests.jl b/stdlib/Markdown/test/runtests.jl index 94d409d9bdfdb..a402ebb9329eb 100644 --- a/stdlib/Markdown/test/runtests.jl +++ b/stdlib/Markdown/test/runtests.jl @@ -1138,3 +1138,23 @@ let m = Markdown.parse("---"), io = IOBuffer() show(io, "text/latex", m) @test String(take!(io)) == "\\rule{\\textwidth}{1pt}\n" end + +# issue #16194: interpolation in md"..." strings +@testset "issue #16194: interpolation in md\"...\" strings" begin + x = "X" + contains_X(md) = occursin(x, sprint(show, MIME("text/plain"), md)) + @test contains_X(md"# $x") # H1 + @test contains_X(md"## $x") # H2 + @test contains_X(md"### $x") # H3 + @test contains_X(md"x = $x") # Paragraph + @test contains_X(md"- $x") # List + @test contains_X(md"[$x](..)") # Link + @test contains_X(md"**$x**") # Bold + @test contains_X(md"*$x*") # Italic + @test contains_X( # Table + md""" + | name | + |------| + | $x | + """) +end diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index addb75df5a5d5..f80c75c33cefa 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,2 +1,2 @@ PKG_BRANCH = master -PKG_SHA1 = aaf4e6e8ab784f7435c1bdc56832bc03e014dedb +PKG_SHA1 = 1542f285243b8ac31e666dee3c6690bdaf26a0be diff --git a/stdlib/SuiteSparse/src/umfpack.jl b/stdlib/SuiteSparse/src/umfpack.jl index c381b11a4b083..b5a08151494ee 100644 --- a/stdlib/SuiteSparse/src/umfpack.jl +++ b/stdlib/SuiteSparse/src/umfpack.jl @@ -333,6 +333,7 @@ for itype in UmfpackIndexTypes if status != UMFPACK_WARNING_singular_matrix umferror(status) end + U.numeric != C_NULL && umfpack_free_numeric(U) U.numeric = tmp[1] return U end @@ -349,6 +350,7 @@ for itype in UmfpackIndexTypes if status != UMFPACK_WARNING_singular_matrix umferror(status) end + U.numeric != C_NULL && umfpack_free_numeric(U) U.numeric = tmp[1] return U end diff --git a/test/clangsa/Makefile b/test/clangsa/Makefile index cc630e82e1cbb..850f9ea76985a 100644 --- a/test/clangsa/Makefile +++ b/test/clangsa/Makefile @@ -1,5 +1,6 @@ SRCDIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) JULIAHOME := $(abspath $(SRCDIR)/../..) +BUILDDIR := . include $(JULIAHOME)/Make.inc check: $(SRCDIR) @@ -7,6 +8,8 @@ check: $(SRCDIR) TESTS = $(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/*.c) $(wildcard $(SRCDIR)/*.cpp)) $(SRCDIR) $(TESTS): + @$(MAKE) -C $(BUILDDIR)/../../src $(build_includedir)/julia/julia_version.h + @$(MAKE) -C $(BUILDDIR)/../../src clangsa PATH=$(build_bindir):$(build_depsbindir):$$PATH \ LD_LIBRARY_PATH="${build_libdir}:$$LD_LIBRARY_PATH" \ CLANGSA_FLAGS="${CLANGSA_FLAGS}" \ diff --git a/test/compiler/codegen.jl b/test/compiler/codegen.jl index f7de112789470..f297142258fc4 100644 --- a/test/compiler/codegen.jl +++ b/test/compiler/codegen.jl @@ -10,14 +10,8 @@ const coverage = (Base.JLOptions().code_coverage > 0) || (Base.JLOptions().mallo const Iptr = sizeof(Int) == 8 ? "i64" : "i32" # `_dump_function` might be more efficient but it doesn't really matter here... -get_llvm(@nospecialize(f), @nospecialize(t), strip_ir_metadata=true, dump_module=false) = - sprint(code_llvm, f, t, strip_ir_metadata, dump_module) - -get_llvm_noopt(@nospecialize(f), @nospecialize(t), strip_ir_metadata=true, dump_module=false) = - InteractiveUtils._dump_function(f, t, - #=native=# false, #=wrapper=# false, #=strip=# strip_ir_metadata, - #=dump_module=# dump_module, #=syntax=#:att, #=optimize=#false) - +get_llvm(@nospecialize(f), @nospecialize(t), raw=true, dump_module=false, optimize=true) = + sprint(code_llvm, f, t, raw, dump_module, optimize) if opt_level > 0 # Make sure getptls call is removed at IR level with optimization on @@ -449,3 +443,23 @@ end str_36422 = "using InteractiveUtils; code_llvm(Base.ht_keyindex, (Dict{NTuple{65,Int64},Nothing}, NTuple{65,Int64}))" @test success(`$(Base.julia_cmd()) --startup-file=no -e $str_36422`) end + +@noinline g37262(x) = (x ? error("intentional") : (0x1, "v", "1", ".", "2")) +function f37262(x) + try + GC.safepoint() + catch + GC.safepoint() + end + try + GC.gc() + return g37262(x) + catch ex + GC.gc() + finally + GC.gc() + end +end +@testset "#37262" begin + @test f37262(Base.inferencebarrier(true)) === nothing +end diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 52ca0bd203d66..4fd9a020252b9 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -99,6 +99,14 @@ tmerge_test(Tuple{}, Tuple{Complex, Vararg{Union{ComplexF32, ComplexF64}}}, @test Core.Compiler.tmerge(Union{Int32, Nothing, Tuple{ComplexF32}}, Union{Int32, Nothing, Tuple{ComplexF32, ComplexF32}}) == Union{Int32, Nothing, Tuple{Vararg{ComplexF32}}} +@test Core.Compiler.tmerge(Base.BitIntegerType, Union{}) === Base.BitIntegerType +@test Core.Compiler.tmerge(Union{}, Base.BitIntegerType) === Base.BitIntegerType + +struct SomethingBits + x::Base.BitIntegerType +end +@test Base.return_types(getproperty, (SomethingBits, Symbol)) == Any[Base.BitIntegerType] + # issue 9770 @noinline x9770() = false function f9770(x) @@ -2617,3 +2625,25 @@ f36531(args...) = tuple((args...)...) @test (sizeof(Ptr),) == sizeof.((Ptr,)) == sizeof.((Ptr{Cvoid},)) @test Core.Compiler.sizeof_tfunc(UnionAll) === Int @test !Core.Compiler.sizeof_nothrow(UnionAll) + +# Use a global constant to rely less on unrelated constant propagation +const const_int32_typename = Int32.name +# Check constant propagation for field of constant `TypeName` +# works for both valid and invalid field names. (Ref #37443) +getfield_const_typename_good1() = getfield(const_int32_typename, 1) +getfield_const_typename_good2() = getfield(const_int32_typename, :name) +getfield_const_typename_bad1() = getfield(const_int32_typename, 0x1) +@eval getfield_const_typename_bad2() = getfield(const_int32_typename, $(())) +for goodf in [getfield_const_typename_good1, getfield_const_typename_good2] + local goodf + local code = code_typed(goodf, Tuple{})[1].first.code + @test code[1] == Expr(:return, QuoteNode(:Int32)) + @test goodf() === :Int32 +end +for badf in [getfield_const_typename_bad1, getfield_const_typename_bad2] + local badf + local code = code_typed(badf, Tuple{})[1].first.code + @test Meta.isexpr(code[1], :call) + @test code[end] == Expr(:unreachable) + @test_throws TypeError badf() +end diff --git a/test/core.jl b/test/core.jl index a44582beda567..baf256a6eaf94 100644 --- a/test/core.jl +++ b/test/core.jl @@ -7233,3 +7233,101 @@ struct X36104; x::Int; end @test fieldtypes(X36104) == (Int,) primitive type P36104 8 end @test_throws ErrorException("invalid redefinition of constant P36104") @eval(primitive type P36104 16 end) + +a37265() = 0 +b37265() = 0 +function c37265(d) + if d == 1 + e = a37265 + elseif d == 2 + e = b37265 + else + try + catch + end + end + e +end +@test_throws UndefVarError c37265(0) +@test c37265(1) === a37265 +@test c37265(2) === b37265 + +function c37265_2(d) + if 0 + e = a37265 + elseif 0 + e = b37265 + else + try + catch + end + end + e +end +@test_throws TypeError c37265_2(0) + +struct PointerImmutable + a::Any + b::Int +end +struct NullableHomogeneousPointerImmutable + x1::PointerImmutable + x2::PointerImmutable + x3::PointerImmutable + NullableHomogeneousPointerImmutable() = new() + NullableHomogeneousPointerImmutable(x1) = new(x1) + NullableHomogeneousPointerImmutable(x1, x2) = new(x1, x2) + NullableHomogeneousPointerImmutable(x1, x2, x3) = new(x1, x2, x3) +end + +function getfield_knownindex_unused(v) + v.x1 + return +end + +function getfield_unknownindex_unused(v, n) + getfield(v, n) + return +end + +function getfield_knownindex_used1(r, v) + fld = v.x1 + r[] += 1 + return fld +end + +function getfield_knownindex_used2(r, v) + fld = v.x1 + r[] += 1 + return fld.a +end + +function getfield_knownindex_used3(r, v) + fld = v.x1 + r[] += 1 + return fld.b +end + +let v = NullableHomogeneousPointerImmutable(), + v2 = NullableHomogeneousPointerImmutable(PointerImmutable(1, 2)), + r = Ref(0) + @test_throws UndefRefError getfield_knownindex_unused(v) + @test_throws UndefRefError getfield_unknownindex_unused(v, 1) + @test_throws UndefRefError getfield_unknownindex_unused(v, :x1) + @test_throws UndefRefError getfield_knownindex_used1(r, v) + @test r[] == 0 + @test_throws UndefRefError getfield_knownindex_used2(r, v) + @test r[] == 0 + @test_throws UndefRefError getfield_knownindex_used3(r, v) + @test r[] == 0 + + @test getfield_knownindex_unused(v2) === nothing + @test getfield_unknownindex_unused(v2, 1) === nothing + @test getfield_unknownindex_unused(v2, :x1) === nothing + @test getfield_knownindex_used1(r, v2) === PointerImmutable(1, 2) + @test r[] == 1 + @test getfield_knownindex_used2(r, v2) === 1 + @test r[] == 2 + @test getfield_knownindex_used3(r, v2) === 2 + @test r[] == 3 +end diff --git a/test/enums.jl b/test/enums.jl index 17ed41b7f1df0..d3c585678c572 100644 --- a/test/enums.jl +++ b/test/enums.jl @@ -200,3 +200,13 @@ end alphabet_z = 26 end @test alphabet_z == Alphabet(26) + +let b = IOBuffer() + show(b, MIME"text/plain"(), Enum) + @test String(take!(b)) == "Enum" + b = IOBuffer() + show(b, MIME"text/plain"(), Union{Alphabet, BritishFood}) + str = String(take!(b)) + p = string(@__MODULE__) + @test str == "Union{$p.Alphabet, $p.BritishFood}" || str == "Union{$p.BritishFood, $p.Alphabet}" +end diff --git a/test/sets.jl b/test/sets.jl index 75e4537972e96..ba28f4d416278 100644 --- a/test/sets.jl +++ b/test/sets.jl @@ -436,6 +436,9 @@ end @test unique!(n -> n % 3, [5, 1, 8, 9, 3, 4, 10, 7, 2, 6]) == [5, 1, 9] @test unique!(iseven, [2, 3, 5, 7, 9]) == [2, 3] @test unique!(x -> x % 2 == 0 ? :even : :odd, [1, 2, 3, 4, 2, 2, 1]) == [1, 2] + + @test isempty(unique!(Union{}[])) + @test eltype(unique!([i for i in ["1"] if i isa Int])) <: Union{} end @testset "allunique" begin diff --git a/test/show.jl b/test/show.jl index cd48ac5dd1888..4e944633c29a8 100644 --- a/test/show.jl +++ b/test/show.jl @@ -235,7 +235,10 @@ for ex in [Expr(:call, :f, Expr(:(=), :x, 1)), Expr(:call, :+, :n, Expr(:kw, :x, 1)), :((a=1,; $(Expr(:(=), :x, 2)))), :(($(Expr(:(=), :a, 1)),; x = 2)), - Expr(:tuple, Expr(:parameters))] + Expr(:tuple, Expr(:parameters)), + Expr(:call, :*, 0, :x01), + Expr(:call, :*, 0, :b01), + Expr(:call, :*, 0, :o01)] @test eval(Meta.parse(repr(ex))) == ex end diff --git a/test/subarray.jl b/test/subarray.jl index d5f7a759e94d0..55c109e62f732 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -656,6 +656,33 @@ end @test _test_27632(view(ones(Int64, (1, 1, 1)), 1, 1, 1)) === nothing end +@testset "issue #37199: 1-d views with offset range indices" begin + b = zeros(6, 3) + b[Base.IdentityUnitRange(4:6), 2] .= 3 + @test b == [zeros(6, 1) [0,0,0,3,3,3] zeros(6,1)] + b[4, Base.IdentityUnitRange(2:3)] .= 4 + @test b == [zeros(6,1) [0,0,0,4,3,3] [0,0,0,4,0,0]] + b[Base.IdentityUnitRange(2:3), :] .= 5 + @test b == [zeros(1, 3); fill(5, 2, 3); [zeros(3) [4,3,3] [4,0,0]]] + b[:, Base.IdentityUnitRange(3:3)] .= 6 + @test b == [[zeros(1, 2); fill(5, 2, 2); [zeros(3) [4,3,3]]] fill(6, 6)] + + A = reshape(1:5*7*11, 11, 7, 5) + inds = (1:4, 2:5, 2, :, fill(3)) + offset(x) = x + offset(r::UnitRange) = Base.IdentityUnitRange(r) + for i1 in inds + for i2 in inds + for i3 in inds + vo = @view A[offset(i1), offset(i2), offset(i3)] + v = @view A[i1, i2, i3] + @test first(vo) == first(v) == first(A[i1, i2, i3]) + @test collect(A[i1, i2, i3]) == collect(vo) == collect(v) + end + end + end +end + @testset "issue #29608; contiguousness" begin @test Base.iscontiguous(view(ones(1), 1)) @test Base.iscontiguous(view(ones(10), 1:10)) diff --git a/test/subtype.jl b/test/subtype.jl index 11589afdf1271..265be9981d320 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -1764,3 +1764,9 @@ end @testintersect(Tuple{Type{T}, AbstractVector{T}} where T, Tuple{Union, F36869{Int64, Missing}}, Tuple{Union, F36869{Int64, Missing}}) + +# issue #37180 +@test !(typeintersect(Tuple{AbstractArray{T}, VecOrMat{T}} where T, Tuple{Array, Any}).body.parameters[1] isa Union) + +# issue #37255 +@test Type{Union{}} == Type{T} where {Union{}<:T<:Union{}} diff --git a/test/syntax.jl b/test/syntax.jl index 9c8b69aa822fd..763d787f9fe06 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -2103,6 +2103,18 @@ end end @test z28789 == 42 +# issue #37126 +@test isempty(Test.collect_test_logs() do + include_string(@__MODULE__, """ + function foo37126() + f(lhs::Integer, rhs::Integer) = nothing + f(lhs::Integer, rhs::AbstractVector{<:Integer}) = nothing + return f + end + struct Bar37126{T<:Real, P<:Real} end + """) + end[1]) + # issue #34673 # check that :toplevel still returns a value when nested inside something else @test eval(Expr(:block, 0, Expr(:toplevel, 43))) == 43 @@ -2283,6 +2295,18 @@ macro m36272() end @test @m36272()(1) == 1 +# issue #37134 +macro m37134() + :(x :: Int -> 62) +end +@test @m37134()(1) == 62 +@test_throws MethodError @m37134()(1.0) == 62 + +macro n37134() + :($(esc(Expr(:tuple, Expr(:..., :x))))->$(esc(:x))) +end +@test @n37134()(2,1) === (2,1) + @testset "unary ± and ∓" begin @test Meta.parse("±x") == Expr(:call, :±, :x) @test Meta.parse("∓x") == Expr(:call, :∓, :x)