diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 6e58f358a6f68..30d2211d6a63a 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1687,16 +1687,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(ctx, 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) { @@ -1787,12 +1789,14 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st } return mark_julia_slot(addr, jfty, tindex, 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, tbaa); } unsigned align = jl_field_align(jt, idx); - return typed_load(ctx, addr, NULL, jfty, tbaa, nullptr, true, align); + return typed_load(ctx, addr, NULL, jfty, tbaa, nullptr, maybe_null, align); } else if (isa(strct.V)) { return jl_cgval_t(); diff --git a/test/core.jl b/test/core.jl index 056f21f45e38d..0911b658383a7 100644 --- a/test/core.jl +++ b/test/core.jl @@ -7330,3 +7330,69 @@ function c37265_2(d) 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