Skip to content

Commit b4fc653

Browse files
committed
detect errors in generated function declarations early
this would have detected #18577 before it was merged
1 parent 9f50a2c commit b4fc653

File tree

6 files changed

+31
-26
lines changed

6 files changed

+31
-26
lines changed

base/multidimensional.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -1047,9 +1047,10 @@ the order that the first of each set of equivalent elements originally appears.
10471047
If `dim` is specified, returns unique regions of the array `itr` along `dim`.
10481048
"""
10491049
@generated function unique{T,N}(A::AbstractArray{T,N}, dim::Int)
1050+
inds = inds -> zeros(UInt, inds)
10501051
quote
10511052
1 <= dim <= $N || return copy(A)
1052-
hashes = similar(inds->zeros(UInt, inds), indices(A, dim))
1053+
hashes = similar($inds, indices(A, dim))
10531054

10541055
# Compute hash for each row
10551056
k = 0

src/alloc.c

+15-3
Original file line numberDiff line numberDiff line change
@@ -485,10 +485,16 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo)
485485
jl_code_info_t *func = NULL;
486486
JL_GC_PUSH4(&ex, &linenum, &sparam_vals, &func);
487487
jl_ptls_t ptls = jl_get_ptls_states();
488+
int last_lineno = jl_lineno;
488489
int last_in = ptls->in_pure_callback;
490+
jl_module_t *last_m = ptls->current_module;
491+
jl_module_t *task_last_m = ptls->current_task->current_module;
489492
assert(jl_svec_len(linfo->def->sparam_syms) == jl_svec_len(sparam_vals));
490493
JL_TRY {
491494
ptls->in_pure_callback = 1;
495+
// need to eval macros in the right module
496+
ptls->current_task->current_module = ptls->current_module = linfo->def->module;
497+
492498
ex = jl_exprn(lambda_sym, 2);
493499

494500
int nargs = linfo->def->nargs;
@@ -522,18 +528,24 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo)
522528
ex = newast;
523529
}
524530

525-
// need to eval macros in the right module, but not give a warning for the `eval` call unless that results in a call to `eval`
526-
func = (jl_code_info_t*)jl_toplevel_eval_in_warn(linfo->def->module, (jl_value_t*)ex, 1);
527-
assert(jl_is_code_info(func));
531+
func = (jl_code_info_t*)jl_expand((jl_value_t*)ex);
532+
if (!jl_is_code_info(func))
533+
jl_error("generated function body is not pure. this likely means it contains a closure or comprehension.");
528534

529535
jl_array_t *stmts = (jl_array_t*)func->code;
530536
for (i = 0, l = jl_array_len(stmts); i < l; i++) {
531537
jl_array_ptr_set(stmts, i, jl_resolve_globals(jl_array_ptr_ref(stmts, i), linfo->def->module));
532538
}
533539
ptls->in_pure_callback = last_in;
540+
jl_lineno = last_lineno;
541+
ptls->current_module = last_m;
542+
ptls->current_task->current_module = task_last_m;
534543
}
535544
JL_CATCH {
536545
ptls->in_pure_callback = last_in;
546+
jl_lineno = last_lineno;
547+
ptls->current_module = last_m;
548+
ptls->current_task->current_module = task_last_m;
537549
jl_rethrow();
538550
}
539551
JL_GC_POP();

src/builtins.c

+4-19
Original file line numberDiff line numberDiff line change
@@ -552,51 +552,36 @@ JL_CALLABLE(jl_f__apply)
552552
// eval -----------------------------------------------------------------------
553553

554554
JL_DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex)
555-
{
556-
return jl_toplevel_eval_in_warn(m, ex, 0);
557-
}
558-
559-
jl_value_t *jl_toplevel_eval_in_warn(jl_module_t *m, jl_value_t *ex, int delay_warn)
560555
{
561556
jl_ptls_t ptls = jl_get_ptls_states();
562-
static int jl_warn_on_eval = 0;
563-
int last_delay_warn = jl_warn_on_eval;
564557
if (m == NULL)
565558
m = jl_main_module;
566559
if (jl_is_symbol(ex))
567560
return jl_eval_global_var(m, (jl_sym_t*)ex);
568-
jl_value_t *v=NULL;
561+
if (ptls->in_pure_callback)
562+
jl_error("eval cannot be used in a generated function");
563+
jl_value_t *v = NULL;
569564
int last_lineno = jl_lineno;
570565
jl_module_t *last_m = ptls->current_module;
571566
jl_module_t *task_last_m = ptls->current_task->current_module;
572-
if (!delay_warn && jl_options.incremental && jl_generating_output()) {
567+
if (jl_options.incremental && jl_generating_output()) {
573568
if (m != last_m) {
574569
jl_printf(JL_STDERR, "WARNING: eval from module %s to %s: \n",
575570
jl_symbol_name(m->name), jl_symbol_name(last_m->name));
576571
jl_static_show(JL_STDERR, ex);
577572
jl_printf(JL_STDERR, "\n ** incremental compilation may be broken for this module **\n\n");
578573
}
579-
else if (jl_warn_on_eval) {
580-
jl_printf(JL_STDERR, "WARNING: eval from staged function in module %s: \n", jl_symbol_name(m->name));
581-
jl_static_show(JL_STDERR, ex);
582-
jl_printf(JL_STDERR, "\n ** incremental compilation may be broken for these modules **\n\n");
583-
}
584574
}
585-
if (ptls->in_pure_callback && !delay_warn)
586-
jl_error("eval cannot be used in a generated function");
587575
JL_TRY {
588-
jl_warn_on_eval = delay_warn && (jl_warn_on_eval || m != last_m); // compute whether a warning was suppressed
589576
ptls->current_task->current_module = ptls->current_module = m;
590577
v = jl_toplevel_eval(ex);
591578
}
592579
JL_CATCH {
593-
jl_warn_on_eval = last_delay_warn;
594580
jl_lineno = last_lineno;
595581
ptls->current_module = last_m;
596582
ptls->current_task->current_module = task_last_m;
597583
jl_rethrow();
598584
}
599-
jl_warn_on_eval = last_delay_warn;
600585
jl_lineno = last_lineno;
601586
ptls->current_module = last_m;
602587
ptls->current_task->current_module = task_last_m;

src/julia_internal.h

-2
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,6 @@ jl_function_t *jl_module_call_func(jl_module_t *m);
324324
int jl_is_submodule(jl_module_t *child, jl_module_t *parent);
325325

326326
jl_value_t *jl_toplevel_eval_flex(jl_value_t *e, int fast, int expanded);
327-
jl_value_t *jl_toplevel_eval_in_warn(jl_module_t *m, jl_value_t *ex,
328-
int delay_warn);
329327

330328
jl_code_info_t *jl_wrap_expr(jl_value_t *expr);
331329
jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e);

test/core.jl

+9
Original file line numberDiff line numberDiff line change
@@ -4578,3 +4578,12 @@ end
45784578
fVararg(x) = Vararg{x}
45794579
gVararg(a::fVararg(Int)) = length(a)
45804580
@test gVararg(1,2,3,4,5) == 5
4581+
4582+
# issue #18577
4583+
@generated f18577() = quote ()->1 end
4584+
@test try
4585+
f18577()
4586+
false
4587+
catch e
4588+
(e::ErrorException).msg
4589+
end == "generated function body is not pure. this likely means it contains a closure or comprehension."

test/staged.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ end
156156
@generated function _g_f_with_inner(x)
157157
:(y->y)
158158
end
159-
@test (_g_f_with_inner(1))(8) == 8
159+
@test_throws ErrorException _g_f_with_inner(1)
160160

161161
# @generated functions errors
162162
global gf_err_ref = Ref{Int}()

0 commit comments

Comments
 (0)