From 63aa793ccaac4fbbe30686b6487f0032826cb5ff Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Tue, 8 Sep 2020 08:30:39 -0400 Subject: [PATCH] Fix `getfield_tfunc` for constant `TypeName` (#37443) The field should be either `Symbol` or `Int`. Ref #37423 Unlike #37423, in additional to worse type info in inference, the missing type check here can actually cause type inference error due to errors in user code. (cherry picked from commit 1378bb6731e75469cbeacb31215bdc180c7ee913) --- base/compiler/tfuncs.jl | 6 +++--- test/compiler/inference.jl | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) 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/test/compiler/inference.jl b/test/compiler/inference.jl index 8db13f2f6663a..4fd9a020252b9 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -2625,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