@@ -221,34 +221,53 @@ function InferenceState(result::InferenceResult, cached::Symbol, interp::GPUInte
221221 src === nothing && return nothing
222222 validate_code_in_debug_mode (result. linfo, src, " lowered" )
223223 validate_globalrefs (interp, result. linfo, src)
224+ validate_code_in_debug_mode (result. linfo, src, " validated" )
225+ errors = Core. Compiler. validate_code (result. linfo, src)
226+ @safe_info " errors" errors src. code
224227 return InferenceState (result, src, cached, interp)
225228end
226229
230+ const UNDEFINED_GLOBAL = " use of an undefined global binding"
231+ const MUTABLE_GLOBAL = " use of a mutable global binding"
232+
227233function validate_globalrefs (interp, mi, src)
228- function validate (x)
234+ # pseudo (single-frame) backtrace pointing to a source code location
235+ function backtrace (i)
236+ loc = src. linetable[i]
237+ [StackTraces. StackFrame (loc. method, loc. file, loc. line, mi, false , false , C_NULL )]
238+ end
239+
240+ function validate (i, x, errors:: Vector{IRError} )
229241 if x isa Expr
230- return Expr (x. head, validate .(x. args))
242+ for y in x. args
243+ validate (i, y, errors)
244+ end
231245 elseif x isa GlobalRef
232246 Base. isbindingresolved (x. mod, x. name) || return
233247 # XXX : when does this happen? do we miss any cases by bailing out early?
234248 # why doesn't calling `Base.resolve(x, force=true)` work?
235249 if ! Base. isdefined (x. mod, x. name)
236- throw ( KernelError (interp . job, " using undefined global: $(x . mod) . $(x . name) " ))
250+ push! (errors, (UNDEFINED_GLOBAL, backtrace (i), x ))
237251 end
238252 if ! Base. isconst (x. mod, x. name)
239- throw ( KernelError (interp . job, " using mutable global: $(x . mod) . $(x . name) " ))
253+ push! (errors, (MUTABLE_GLOBAL, backtrace (i), x ))
240254 end
241- # XXX : can we use KernelError? and make the validation conditional? both are
242- # complicated by the fact that we don't have the CompilerJob here,
243- # and that inference results can be cached across jobs.
255+
256+ # TODO : make the validation conditional, but make sure we don't cache invalid IR
244257
245258 # TODO : perform more validation? e.g. disallow Arrays and other CPU values?
246- # probably requires an interface, so again access to the CompilerJob
247- # (as a CPU-back-end would still support such values).
248259 end
260+
261+ return
249262 end
250263
251- validate .(src. code)
264+ errors = IRError[]
265+ for (i, x) in enumerate (src. code)
266+ validate (i, x, errors)
267+ end
268+ if ! isempty (errors)
269+ throw (InvalidIRError (interp. job, errors))
270+ end
252271
253272 return
254273end
0 commit comments