781781# - false: eligible for semi-concrete evaluation
782782# - nothing: not eligible for either of it
783783function concrete_eval_eligible (interp:: AbstractInterpreter ,
784- @nospecialize (f), result:: MethodCallResult , arginfo:: ArgInfo )
784+ @nospecialize (f), result:: MethodCallResult , arginfo:: ArgInfo , sv :: InferenceState )
785785 # disable all concrete-evaluation if this function call is tainted by some overlayed
786786 # method since currently there is no direct way to execute overlayed methods
787+ if inbounds_option () === :off
788+ # Disable concrete evaluation in `--check-bounds=no` mode, since we cannot be sure
789+ # that inferred effects are accurate.
790+ return nothing
791+ elseif ! result. effects. noinbounds && stmt_taints_inbounds_consistency (sv)
792+ # If the current statement is @inbounds or we propagate inbounds, the call's consistency
793+ # is tainted and not consteval eligible.
794+ return nothing
795+ end
787796 isoverlayed (method_table (interp)) && ! is_nonoverlayed (result. effects) && return nothing
788797 if f != = nothing && result. edge != = nothing && is_foldable (result. effects)
789798 if is_all_const_arg (arginfo, #= start=# 2 )
824833function concrete_eval_call (interp:: AbstractInterpreter ,
825834 @nospecialize (f), result:: MethodCallResult , arginfo:: ArgInfo , si:: StmtInfo ,
826835 sv:: InferenceState , invokecall:: Union{Nothing,InvokeCall} = nothing )
827- eligible = concrete_eval_eligible (interp, f, result, arginfo)
836+ eligible = concrete_eval_eligible (interp, f, result, arginfo, sv )
828837 eligible === nothing && return false
829838 if eligible
830839 args = collect_const_args (arginfo, #= start=# 2 )
@@ -2026,22 +2035,32 @@ function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, vtypes::V
20262035 nothing
20272036end
20282037
2029- function abstract_eval_value_expr (interp:: AbstractInterpreter , e:: Expr , sv:: Union{InferenceState, IRCode} )
2038+ function abstract_eval_value_expr (interp:: AbstractInterpreter , e:: Expr , vtypes:: Union{VarTable, Nothing} , sv:: Union{InferenceState, IRCode} )
2039+ rt = Any
20302040 head = e. head
20312041 if head === :static_parameter
20322042 n = e. args[1 ]:: Int
2033- t = Any
20342043 if 1 <= n <= length (sv. sptypes)
2035- t = sv. sptypes[n]
2044+ rt = sv. sptypes[n]
20362045 end
2037- return t
20382046 elseif head === :boundscheck
2039- return Bool
2047+ if isa (sv, InferenceState)
2048+ flag = sv. src. ssaflags[sv. currpc]
2049+ # If there is no particular @inbounds for this function, then we only taint `noinbounds`,
2050+ # which will subsequently taint consistency if this function is called from another
2051+ # function that uses `@inbounds`. However, if this :boundscheck is itself within an
2052+ # `@inbounds` region, its value depends on `--check-bounds`, so we need to taint
2053+ # consistency here also.
2054+ merge_effects! (interp, sv, Effects (EFFECTS_TOTAL; noinbounds= false ,
2055+ consistent = (flag & IR_FLAG_INBOUNDS) != 0 ? ALWAYS_FALSE : ALWAYS_TRUE))
2056+ end
2057+ rt = Bool
2058+ elseif head === :inbounds
2059+ @assert false && " Expected this to have been moved into flags"
20402060 elseif head === :the_exception
20412061 merge_effects! (interp, sv, Effects (EFFECTS_TOTAL; consistent= ALWAYS_FALSE))
2042- return Any
20432062 end
2044- return Any
2063+ return rt
20452064end
20462065
20472066function abstract_eval_special_value (interp:: AbstractInterpreter , @nospecialize (e), vtypes:: Union{VarTable, Nothing} , sv:: Union{InferenceState, IRCode} )
@@ -2071,7 +2090,7 @@ end
20712090
20722091function abstract_eval_value (interp:: AbstractInterpreter , @nospecialize (e), vtypes:: Union{VarTable, Nothing} , sv:: Union{InferenceState, IRCode} )
20732092 if isa (e, Expr)
2074- return abstract_eval_value_expr (interp, e, sv)
2093+ return abstract_eval_value_expr (interp, e, vtypes, sv)
20752094 else
20762095 typ = abstract_eval_special_value (interp, e, vtypes, sv)
20772096 return collect_limitations! (typ, sv)
@@ -2112,7 +2131,6 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp
21122131 arginfo = ArgInfo (ea, argtypes)
21132132 si = StmtInfo (isa (sv, IRCode) ? true : ! call_result_unused (sv, sv. currpc))
21142133 (; rt, effects, info) = abstract_call (interp, arginfo, si, sv)
2115- merge_effects! (interp, sv, effects)
21162134 if isa (sv, InferenceState)
21172135 sv. stmt_info[sv. currpc] = info
21182136 end
@@ -2176,7 +2194,6 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp
21762194 nothrow = false
21772195 end
21782196 effects = Effects (EFFECTS_TOTAL; consistent, nothrow)
2179- merge_effects! (interp, sv, effects)
21802197 elseif ehead === :splatnew
21812198 t, isexact = instanceof_tfunc (abstract_eval_value (interp, e. args[1 ], vtypes, sv))
21822199 nothrow = false # TODO : More precision
@@ -2195,7 +2212,6 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp
21952212 end
21962213 consistent = ! ismutabletype (t) ? ALWAYS_TRUE : CONSISTENT_IF_NOTRETURNED
21972214 effects = Effects (EFFECTS_TOTAL; consistent, nothrow)
2198- merge_effects! (interp, sv, effects)
21992215 elseif ehead === :new_opaque_closure
22002216 t = Union{}
22012217 effects = Effects () # TODO
@@ -2223,20 +2239,16 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp
22232239 elseif ehead === :foreigncall
22242240 (;rt, effects) = abstract_eval_foreigncall (interp, e, vtypes, sv, mi)
22252241 t = rt
2226- merge_effects! (interp, sv, effects)
22272242 elseif ehead === :cfunction
22282243 effects = EFFECTS_UNKNOWN
2229- merge_effects! (interp, sv, effects)
22302244 t = e. args[1 ]
22312245 isa (t, Type) || (t = Any)
22322246 abstract_eval_cfunction (interp, e, vtypes, sv)
22332247 elseif ehead === :method
22342248 t = (length (e. args) == 1 ) ? Any : Nothing
22352249 effects = EFFECTS_UNKNOWN
2236- merge_effects! (interp, sv, effects)
22372250 elseif ehead === :copyast
22382251 effects = EFFECTS_UNKNOWN
2239- merge_effects! (interp, sv, effects)
22402252 t = abstract_eval_value (interp, e. args[1 ], vtypes, sv)
22412253 if t isa Const && t. val isa Expr
22422254 # `copyast` makes copies of Exprs
@@ -2247,6 +2259,7 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp
22472259 elseif ehead === :isdefined
22482260 sym = e. args[1 ]
22492261 t = Bool
2262+ effects = EFFECTS_TOTAL
22502263 if isa (sym, SlotNumber)
22512264 vtyp = vtypes[slot_id (sym)]
22522265 if vtyp. typ === Bottom
@@ -2275,9 +2288,9 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp
22752288 @label always_throw
22762289 t = Bottom
22772290 effects = EFFECTS_THROWS
2278- merge_effects! (interp, sv, effects)
22792291 else
2280- t = abstract_eval_value_expr (interp, e, sv)
2292+ t = abstract_eval_value_expr (interp, e, vtypes, sv)
2293+ effects = EFFECTS_TOTAL
22812294 end
22822295 return RTEffects (t, effects)
22832296end
@@ -2319,6 +2332,11 @@ function abstract_eval_phi(interp::AbstractInterpreter, phi::PhiNode, vtypes::Un
23192332 return rt
23202333end
23212334
2335+ function stmt_taints_inbounds_consistency (sv:: InferenceState )
2336+ flag = sv. src. ssaflags[sv. currpc]
2337+ return sv. src. propagate_inbounds || (flag & IR_FLAG_INBOUNDS) != 0
2338+ end
2339+
23222340function abstract_eval_statement (interp:: AbstractInterpreter , @nospecialize (e), vtypes:: VarTable , sv:: InferenceState )
23232341 if ! isa (e, Expr)
23242342 if isa (e, PhiNode)
@@ -2327,6 +2345,18 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
23272345 return abstract_eval_special_value (interp, e, vtypes, sv)
23282346 end
23292347 (;rt, effects) = abstract_eval_statement_expr (interp, e, vtypes, sv, nothing )
2348+ if ! effects. noinbounds
2349+ flag = sv. src. ssaflags[sv. currpc]
2350+ if ! sv. src. propagate_inbounds
2351+ # The callee read our inbounds flag, but unless we propagate inbounds,
2352+ # we ourselves don't read our parent's inbounds.
2353+ effects = Effects (effects; noinbounds= true )
2354+ end
2355+ if (flag & IR_FLAG_INBOUNDS) != 0
2356+ effects = Effects (effects; consistent= ALWAYS_FALSE)
2357+ end
2358+ end
2359+ merge_effects! (interp, sv, effects)
23302360 e = e:: Expr
23312361 @assert ! isa (rt, TypeVar) " unhandled TypeVar"
23322362 rt = maybe_singleton_const (rt)
0 commit comments