diff --git a/src/builtins.c b/src/builtins.c index f40d694d23529..7ef93faaa6368 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1487,22 +1487,38 @@ static int equiv_field_types(jl_value_t *old, jl_value_t *ft) return 1; } +// If a field can reference its enclosing type, then the inlining +// recursive depth is not statically bounded for some layouts, so we cannot +// inline it. The only way fields can reference this type (due to +// syntax-enforced restrictions) is via being passed as a type parameter. Thus +// we can conservatively check this by examining only the parameters of the +// dependent types. +// affects_layout is a hack introduced by #35275 to workaround a problem +// introduced by #34223: it checks whether we will potentially need to +// compute the layout of the object before we have fully computed the types of +// the fields during recursion over the allocation of the parameters for the +// field types (of the concrete subtypes) static int references_name(jl_value_t *p, jl_typename_t *name, int affects_layout) JL_NOTSAFEPOINT { if (jl_is_uniontype(p)) return references_name(((jl_uniontype_t*)p)->a, name, affects_layout) || references_name(((jl_uniontype_t*)p)->b, name, affects_layout); if (jl_is_unionall(p)) - return references_name((jl_value_t*)((jl_unionall_t*)p)->var, name, 0) || + return references_name((jl_value_t*)((jl_unionall_t*)p)->var->lb, name, 0) || + references_name((jl_value_t*)((jl_unionall_t*)p)->var->ub, name, 0) || references_name(((jl_unionall_t*)p)->body, name, affects_layout); if (jl_is_typevar(p)) - return references_name(((jl_tvar_t*)p)->ub, name, 0) || - references_name(((jl_tvar_t*)p)->lb, name, 0); + return 0; // already checked by unionall, if applicable if (jl_is_datatype(p)) { jl_datatype_t *dp = (jl_datatype_t*)p; if (affects_layout && dp->name == name) return 1; - affects_layout = dp->types == NULL || jl_svec_len(dp->types) != 0; + // affects_layout checks whether we will need to attempt to layout this + // type (based on whether all copies of it have the same layout) in + // that case, we still need to check the recursive parameters for + // layout recursion happening also, but we know it won't itself cause + // problems for the layout computation + affects_layout = ((jl_datatype_t*)jl_unwrap_unionall(dp->name->wrapper))->layout == NULL; size_t i, l = jl_nparams(p); for (i = 0; i < l; i++) { if (references_name(jl_tparam(p, i), name, affects_layout)) @@ -1537,16 +1553,21 @@ JL_CALLABLE(jl_f__typebody) else { dt->types = (jl_svec_t*)ft; jl_gc_wb(dt, ft); - if (!dt->name->mutabl) { - dt->name->mayinlinealloc = 1; + // If a supertype can reference the same type, then we may not be + // able to compute the layout of the object before needing to + // publish it, so we must assume it cannot be inlined, if that + // check passes, then we also still need to check the fields too. + if (!dt->name->mutabl && !references_name((jl_value_t*)dt->super, dt->name, 1)) { + int mayinlinealloc = 1; size_t i, nf = jl_svec_len(ft); for (i = 0; i < nf; i++) { jl_value_t *fld = jl_svecref(ft, i); if (references_name(fld, dt->name, 1)) { - dt->name->mayinlinealloc = 0; + mayinlinealloc = 0; break; } } + dt->name->mayinlinealloc = mayinlinealloc; } } } diff --git a/test/core.jl b/test/core.jl index c27a0008fa727..0a92c3e1aeef3 100644 --- a/test/core.jl +++ b/test/core.jl @@ -7219,8 +7219,17 @@ end struct B33954 x::Q33954{B33954} end -@test_broken isbitstype(Tuple{B33954}) -@test_broken isbitstype(B33954) +@test isbitstype(Tuple{B33954}) +@test isbitstype(B33954) + +struct A41503{d} + e::d +end +struct B41503{j,k} <: AbstractArray{A41503{B41503{Any,k}},Any} + l::k +end +@test !isbitstype(B41503{Any,Any}) +@test_broken isbitstype(B41503{Any,Int}) struct B40050 <: Ref{Tuple{B40050}} end