Skip to content

Commit fd70b3a

Browse files
committed
Don't let setglobal! implicitly create bindings
PR #44231 (part of Julia 1.9) introduced the ability to modify globals with `Mod.sym = val` syntax. However, the intention of this syntax was always to modify *existing* globals in other modules. Unfortunately, as implemented, it also implicitly creates new bindings in the other module, even if the binding was not previously declared. This was not intended, but it's a bit of a syntax corner case, so nobody caught it at the time. After some extensive discussions and taking into account the near future direction we want to go with bindings (#54654 for both), the consensus was reached that we should try to undo the implicit creation of bindings (but not the ability to assign the *value* of globals in other modules). Note that this was always an error until Julia 1.9, so hopefully it hasn't crept into too many packages yet. We'll see what pkgeval says. If use is extensive, we may want to consider a softer removal strategy. Across base and stdlib, there's two cases affected by this change: 1. A left over debug statement in `precompile` that wanted to assign a new variable in Base for debugging. Removed in this PR. 2. Distributed wanting to create new bindings. This is a legimitate use case for wanting to create bindings in other modules. This is fixed in JuliaLang/Distributed.jl#102. As noted in that PR, the recommended replacement where implicit binding creation is desired is: ``` Core.eval(mod, Expr(:global, sym)) invokelatest(setglobal!, mod, sym, val) ``` The `invokelatest` is not presently required, but may be needed by #54654, so it's included in the recommendation now. Fixes #54607
1 parent 75951ec commit fd70b3a

12 files changed

+96
-33
lines changed

base/docs/basedocs.jl

+8-3
Original file line numberDiff line numberDiff line change
@@ -2510,12 +2510,17 @@ cases.
25102510
See also [`setproperty!`](@ref Base.setproperty!) and [`getglobal`](@ref)
25112511
25122512
# Examples
2513-
```jldoctest
2514-
julia> module M end;
2513+
```jldoctest; filter = r"Stacktrace:(\\n \\[[0-9]+\\].*)*"
2514+
julia> module M; global a; end;
25152515
25162516
julia> M.a # same as `getglobal(M, :a)`
25172517
ERROR: UndefVarError: `a` not defined in `M`
2518-
Suggestion: check for spelling errors or missing imports.
2518+
Suggestion: add an appropriate import or assignment. This global was declared but not assigned.
2519+
Stacktrace:
2520+
[1] getproperty(x::Module, f::Symbol)
2521+
@ Base ./Base.jl:42
2522+
[2] top-level scope
2523+
@ none:1
25192524
25202525
julia> setglobal!(M, :a, 1)
25212526
1

doc/src/manual/embedding.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ per pointer using
412412
```c
413413
jl_module_t *mod = jl_main_module;
414414
jl_sym_t *var = jl_symbol("var");
415-
jl_binding_t *bp = jl_get_binding_wr(mod, var);
415+
jl_binding_t *bp = jl_get_binding_wr(mod, var, 1);
416416
jl_checked_assignment(bp, mod, var, val);
417417
```
418418

src/builtins.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -1355,7 +1355,7 @@ JL_CALLABLE(jl_f_setglobal)
13551355
jl_atomic_error("setglobal!: module binding cannot be written non-atomically");
13561356
else if (order >= jl_memory_order_seq_cst)
13571357
jl_fence();
1358-
jl_binding_t *b = jl_get_binding_wr(mod, var);
1358+
jl_binding_t *b = jl_get_binding_wr(mod, var, 0);
13591359
jl_checked_assignment(b, mod, var, args[2]); // release store
13601360
if (order >= jl_memory_order_seq_cst)
13611361
jl_fence();
@@ -1393,7 +1393,7 @@ JL_CALLABLE(jl_f_set_binding_type)
13931393
JL_TYPECHK(set_binding_type!, symbol, (jl_value_t*)s);
13941394
jl_value_t *ty = nargs == 2 ? (jl_value_t*)jl_any_type : args[2];
13951395
JL_TYPECHK(set_binding_type!, type, ty);
1396-
jl_binding_t *b = jl_get_binding_wr(m, s);
1396+
jl_binding_t *b = jl_get_binding_wr(m, s, 0);
13971397
jl_value_t *old_ty = NULL;
13981398
if (jl_atomic_cmpswap_relaxed(&b->ty, &old_ty, ty)) {
13991399
jl_gc_wb(b, ty);
@@ -1420,7 +1420,7 @@ JL_CALLABLE(jl_f_swapglobal)
14201420
if (order == jl_memory_order_notatomic)
14211421
jl_atomic_error("swapglobal!: module binding cannot be written non-atomically");
14221422
// is seq_cst already, no fence needed
1423-
jl_binding_t *b = jl_get_binding_wr(mod, var);
1423+
jl_binding_t *b = jl_get_binding_wr(mod, var, 0);
14241424
return jl_checked_swap(b, mod, var, args[2]);
14251425
}
14261426

@@ -1438,7 +1438,7 @@ JL_CALLABLE(jl_f_modifyglobal)
14381438
JL_TYPECHK(modifyglobal!, symbol, (jl_value_t*)var);
14391439
if (order == jl_memory_order_notatomic)
14401440
jl_atomic_error("modifyglobal!: module binding cannot be written non-atomically");
1441-
jl_binding_t *b = jl_get_binding_wr(mod, var);
1441+
jl_binding_t *b = jl_get_binding_wr(mod, var, 0);
14421442
// is seq_cst already, no fence needed
14431443
return jl_checked_modify(b, mod, var, args[2], args[3]);
14441444
}
@@ -1467,7 +1467,7 @@ JL_CALLABLE(jl_f_replaceglobal)
14671467
jl_atomic_error("replaceglobal!: module binding cannot be written non-atomically");
14681468
if (failure_order == jl_memory_order_notatomic)
14691469
jl_atomic_error("replaceglobal!: module binding cannot be accessed non-atomically");
1470-
jl_binding_t *b = jl_get_binding_wr(mod, var);
1470+
jl_binding_t *b = jl_get_binding_wr(mod, var, 0);
14711471
// is seq_cst already, no fence needed
14721472
return jl_checked_replace(b, mod, var, args[2], args[3]);
14731473
}
@@ -1496,7 +1496,7 @@ JL_CALLABLE(jl_f_setglobalonce)
14961496
jl_atomic_error("setglobalonce!: module binding cannot be written non-atomically");
14971497
if (failure_order == jl_memory_order_notatomic)
14981498
jl_atomic_error("setglobalonce!: module binding cannot be accessed non-atomically");
1499-
jl_binding_t *b = jl_get_binding_wr(mod, var);
1499+
jl_binding_t *b = jl_get_binding_wr(mod, var, 0);
15001500
// is seq_cst already, no fence needed
15011501
jl_value_t *old = jl_checked_assignonce(b, mod, var, args[2]);
15021502
return old == NULL ? jl_true : jl_false;

src/codegen.cpp

+26-13
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,7 @@ static const auto jlgetbindingwrorerror_func = new JuliaFunction<>{
946946
[](LLVMContext &C) {
947947
auto T_pjlvalue = JuliaType::get_pjlvalue_ty(C);
948948
return FunctionType::get(T_pjlvalue,
949-
{T_pjlvalue, T_pjlvalue}, false);
949+
{T_pjlvalue, T_pjlvalue, getInt32Ty(C)}, false);
950950
},
951951
nullptr,
952952
};
@@ -2100,7 +2100,7 @@ static Type *julia_type_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed
21002100
static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value *fval, StringRef name, jl_value_t *sig, jl_value_t *jlrettype, bool is_opaque_closure, bool gcstack_arg, BitVector *used_arguments=nullptr, size_t *args_begin=nullptr);
21012101
static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval = -1);
21022102
static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t *s,
2103-
jl_binding_t **pbnd, bool assign);
2103+
jl_binding_t **pbnd, bool assign, bool alloc);
21042104
static jl_cgval_t emit_checked_var(jl_codectx_t &ctx, Value *bp, jl_sym_t *name, jl_value_t *scope, bool isvol, MDNode *tbaa);
21052105
static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i);
21062106
static Value *emit_condition(jl_codectx_t &ctx, const jl_cgval_t &condV, const Twine &msg);
@@ -3190,7 +3190,7 @@ static jl_value_t *jl_ensure_rooted(jl_codectx_t &ctx, jl_value_t *val)
31903190
static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *name, AtomicOrdering order)
31913191
{
31923192
jl_binding_t *bnd = NULL;
3193-
Value *bp = global_binding_pointer(ctx, mod, name, &bnd, false);
3193+
Value *bp = global_binding_pointer(ctx, mod, name, &bnd, false, false);
31943194
if (bp == NULL)
31953195
return jl_cgval_t();
31963196
bp = julia_binding_pvalue(ctx, bp);
@@ -3209,10 +3209,10 @@ static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *
32093209
static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *sym, jl_cgval_t rval, const jl_cgval_t &cmp,
32103210
AtomicOrdering Order, AtomicOrdering FailOrder,
32113211
bool issetglobal, bool isreplaceglobal, bool isswapglobal, bool ismodifyglobal, bool issetglobalonce,
3212-
const jl_cgval_t *modifyop)
3212+
const jl_cgval_t *modifyop, bool alloc)
32133213
{
32143214
jl_binding_t *bnd = NULL;
3215-
Value *bp = global_binding_pointer(ctx, mod, sym, &bnd, true);
3215+
Value *bp = global_binding_pointer(ctx, mod, sym, &bnd, true, alloc);
32163216
if (bp == NULL)
32173217
return jl_cgval_t();
32183218
if (bnd && !bnd->constp) {
@@ -3761,7 +3761,8 @@ static bool emit_f_opglobal(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
37613761
isswapglobal,
37623762
ismodifyglobal,
37633763
issetglobalonce,
3764-
modifyop);
3764+
modifyop,
3765+
false);
37653766
return true;
37663767
}
37673768
}
@@ -5448,7 +5449,7 @@ static void emit_hasnofield_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_sym_t *
54485449
// if the reference currently bound or assign == true,
54495450
// pbnd will also be assigned with the binding address
54505451
static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t *s,
5451-
jl_binding_t **pbnd, bool assign)
5452+
jl_binding_t **pbnd, bool assign, bool alloc)
54525453
{
54535454
jl_binding_t *b = jl_get_module_binding(m, s, 1);
54545455
if (assign) {
@@ -5478,9 +5479,17 @@ static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t
54785479
ctx.builder.CreateCondBr(iscached, have_val, not_found);
54795480
not_found->insertInto(ctx.f);
54805481
ctx.builder.SetInsertPoint(not_found);
5481-
Value *bval = ctx.builder.CreateCall(prepare_call(assign ? jlgetbindingwrorerror_func : jlgetbindingorerror_func),
5482-
{ literal_pointer_val(ctx, (jl_value_t*)m),
5483-
literal_pointer_val(ctx, (jl_value_t*)s) });
5482+
Value *bval = nullptr;
5483+
if (assign) {
5484+
bval = ctx.builder.CreateCall(prepare_call(jlgetbindingwrorerror_func),
5485+
{ literal_pointer_val(ctx, (jl_value_t*)m),
5486+
literal_pointer_val(ctx, (jl_value_t*)s),
5487+
ConstantInt::get(getInt32Ty(ctx.builder.getContext()), alloc)});
5488+
} else {
5489+
bval = ctx.builder.CreateCall(prepare_call(jlgetbindingorerror_func),
5490+
{ literal_pointer_val(ctx, (jl_value_t*)m),
5491+
literal_pointer_val(ctx, (jl_value_t*)s)});
5492+
}
54845493
setName(ctx.emission_context, bval, jl_symbol_name(m->name) + StringRef(".") + jl_symbol_name(s) + ".found");
54855494
ctx.builder.CreateAlignedStore(bval, bindinggv, Align(sizeof(void*)))->setOrdering(AtomicOrdering::Release);
54865495
ctx.builder.CreateBr(have_val);
@@ -5497,7 +5506,8 @@ static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t
54975506
// this will fail at runtime, so defer to the runtime to create the error
54985507
ctx.builder.CreateCall(prepare_call(jlgetbindingwrorerror_func),
54995508
{ literal_pointer_val(ctx, (jl_value_t*)m),
5500-
literal_pointer_val(ctx, (jl_value_t*)s) });
5509+
literal_pointer_val(ctx, (jl_value_t*)s),
5510+
ConstantInt::get(getInt32Ty(ctx.builder.getContext()), alloc) });
55015511
CreateTrap(ctx.builder);
55025512
return NULL;
55035513
}
@@ -5992,17 +6002,20 @@ static void emit_assignment(jl_codectx_t &ctx, jl_value_t *l, jl_value_t *r, ssi
59926002

59936003
jl_module_t *mod;
59946004
jl_sym_t *sym;
6005+
bool toplevel = jl_is_module(ctx.linfo->def.value);
6006+
bool alloc = toplevel;
59956007
if (jl_is_symbol(l)) {
59966008
mod = ctx.module;
59976009
sym = (jl_sym_t*)l;
59986010
}
59996011
else {
60006012
assert(jl_is_globalref(l));
6013+
alloc &= jl_globalref_mod(l) == ctx.module;
60016014
mod = jl_globalref_mod(l);
60026015
sym = jl_globalref_name(l);
60036016
}
60046017
emit_globalop(ctx, mod, sym, rval_info, jl_cgval_t(), AtomicOrdering::Release, AtomicOrdering::NotAtomic,
6005-
true, false, false, false, false, nullptr);
6018+
true, false, false, false, false, nullptr, alloc);
60066019
// Global variable. Does not need debug info because the debugger knows about
60076020
// its memory location.
60086021
}
@@ -6456,7 +6469,7 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_
64566469
}
64576470
if (jl_is_symbol(sym)) {
64586471
jl_binding_t *bnd = NULL;
6459-
Value *bp = global_binding_pointer(ctx, mod, sym, &bnd, true);
6472+
Value *bp = global_binding_pointer(ctx, mod, sym, &bnd, true, true);
64606473
if (bp)
64616474
ctx.builder.CreateCall(prepare_call(jldeclareconst_func),
64626475
{ bp, literal_pointer_val(ctx, (jl_value_t*)mod), literal_pointer_val(ctx, (jl_value_t*)sym) });

src/interpreter.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -571,17 +571,21 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip,
571571
else {
572572
jl_module_t *modu;
573573
jl_sym_t *sym;
574+
// Plain assignment is allowed to create bindings at
575+
// toplevel and only for the current module
576+
int alloc = toplevel;
574577
if (jl_is_globalref(lhs)) {
575578
modu = jl_globalref_mod(lhs);
576579
sym = jl_globalref_name(lhs);
580+
alloc &= modu == s->module;
577581
}
578582
else {
579583
assert(jl_is_symbol(lhs));
580584
modu = s->module;
581585
sym = (jl_sym_t*)lhs;
582586
}
583587
JL_GC_PUSH1(&rhs);
584-
jl_binding_t *b = jl_get_binding_wr(modu, sym);
588+
jl_binding_t *b = jl_get_binding_wr(modu, sym, alloc);
585589
jl_checked_assignment(b, modu, sym, rhs);
586590
JL_GC_POP();
587591
}

src/julia-syntax.scm

+1
Original file line numberDiff line numberDiff line change
@@ -4233,6 +4233,7 @@ f(x) = yt(x)
42334233
(put! globals ref #t)
42344234
`(block
42354235
(toplevel-only set_binding_type! ,(cadr e))
4236+
(global ,ref)
42364237
(call (core set_binding_type!) ,(cadr ref) (inert ,(caddr ref)) ,(caddr e))))
42374238
`(call (core typeassert) ,@(cdr e))))
42384239
fname lam namemap defined toplevel interp opaq globals locals))))

src/julia.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1947,7 +1947,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var
19471947
JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var);
19481948
JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var);
19491949
// get binding for assignment
1950-
JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var);
1950+
JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int alloc);
19511951
JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var);
19521952
JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var);
19531953
JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var);

src/module.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -219,13 +219,16 @@ static void check_safe_newbinding(jl_module_t *m, jl_sym_t *var)
219219
static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b, jl_module_t *m, jl_sym_t *var) JL_GLOBALLY_ROOTED;
220220

221221
// get binding for assignment
222-
JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var)
222+
JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int alloc)
223223
{
224224
jl_binding_t *b = jl_get_module_binding(m, var, 1);
225225
jl_binding_t *b2 = jl_atomic_load_relaxed(&b->owner);
226226
if (b2 != b) {
227-
if (b2 == NULL)
227+
if (b2 == NULL) {
228228
check_safe_newbinding(m, var);
229+
if (!alloc)
230+
jl_errorf("Global %s.%s does not exist and cannot be assigned. Declare it using `global` before attempting assignment.", jl_symbol_name(m->name), jl_symbol_name(var));
231+
}
229232
if (b2 != NULL || (!jl_atomic_cmpswap(&b->owner, &b2, b) && b2 != b)) {
230233
jl_module_t *from = jl_binding_dbgmodule(b, m, var);
231234
if (from == m)
@@ -793,7 +796,7 @@ JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m, jl_sym_t *var)
793796

794797
JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT)
795798
{
796-
jl_binding_t *bp = jl_get_binding_wr(m, var);
799+
jl_binding_t *bp = jl_get_binding_wr(m, var, 0);
797800
jl_checked_assignment(bp, m, var, val);
798801
}
799802

src/toplevel.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex
155155
}
156156
}
157157
else {
158-
jl_binding_t *b = jl_get_binding_wr(parent_module, name);
158+
jl_binding_t *b = jl_get_binding_wr(parent_module, name, 1);
159159
jl_declare_constant(b, parent_module, name);
160160
jl_value_t *old = NULL;
161161
if (!jl_atomic_cmpswap(&b->value, &old, (jl_value_t*)newm)) {
@@ -325,7 +325,7 @@ void jl_eval_global_expr(jl_module_t *m, jl_expr_t *ex, int set_type) {
325325
gs = (jl_sym_t*)arg;
326326
}
327327
if (!jl_binding_resolved_p(gm, gs)) {
328-
jl_binding_t *b = jl_get_binding_wr(gm, gs);
328+
jl_binding_t *b = jl_get_binding_wr(gm, gs, 1);
329329
if (set_type) {
330330
jl_value_t *old_ty = NULL;
331331
// maybe set the type too, perhaps
@@ -638,7 +638,7 @@ static void import_module(jl_module_t *JL_NONNULL m, jl_module_t *import, jl_sym
638638
jl_symbol_name(name), jl_symbol_name(m->name));
639639
}
640640
else {
641-
b = jl_get_binding_wr(m, name);
641+
b = jl_get_binding_wr(m, name, 1);
642642
}
643643
jl_declare_constant(b, m, name);
644644
jl_checked_assignment(b, m, name, (jl_value_t*)import);
@@ -897,7 +897,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val
897897
gm = m;
898898
gs = (jl_sym_t*)arg;
899899
}
900-
jl_binding_t *b = jl_get_binding_wr(gm, gs);
900+
jl_binding_t *b = jl_get_binding_wr(gm, gs, 1);
901901
jl_declare_constant(b, gm, gs);
902902
JL_GC_POP();
903903
return jl_nothing;

test/core.jl

+1
Original file line numberDiff line numberDiff line change
@@ -8145,6 +8145,7 @@ end
81458145
@test_broken Int isa Union{Union, Type{Union{Int,T1}} where {T1}}
81468146

81478147
let M = @__MODULE__
8148+
Core.eval(M, :(global a_typed_global))
81488149
@test Core.set_binding_type!(M, :a_typed_global, Tuple{Union{Integer,Nothing}}) === nothing
81498150
@test Core.get_binding_type(M, :a_typed_global) === Tuple{Union{Integer,Nothing}}
81508151
@test Core.set_binding_type!(M, :a_typed_global, Tuple{Union{Integer,Nothing}}) === nothing

test/precompile.jl

-1
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,6 @@ precompile_test_harness("code caching") do dir
10231023
@test mi.specTypes.parameters[end] === Integer ? !hv : hv
10241024
end
10251025

1026-
setglobal!(Main, :inval, invalidations)
10271026
idxs = findall(==("verify_methods"), invalidations)
10281027
idxsbits = filter(idxs) do i
10291028
mi = invalidations[i-1]

test/syntax.jl

+37
Original file line numberDiff line numberDiff line change
@@ -3699,3 +3699,40 @@ end
36993699
@test f54701() == 3
37003700
@test !@isdefined(a54701)
37013701
@test !@isdefined(b54701)
3702+
3703+
# Issue #54607 - binding creation in foreign modules should not be permitted
3704+
module Foreign54607
3705+
# Syntactic, not dynamic
3706+
try_to_create_binding1() = (Foreign54607.foo = 2)
3707+
@eval try_to_create_binding2() = ($(GlobalRef(Foreign54607, :foo)) = 2)
3708+
function global_create_binding()
3709+
global bar
3710+
bar = 3
3711+
end
3712+
baz = 4
3713+
begin;
3714+
@Base.Experimental.force_compile
3715+
compiled_assign = 5
3716+
end
3717+
@eval $(GlobalRef(Foreign54607, :gr_assign)) = 6
3718+
end
3719+
@test_throws ErrorException (Foreign54607.foo = 1)
3720+
@test_throws ErrorException Foreign54607.try_to_create_binding1()
3721+
@test_throws ErrorException Foreign54607.try_to_create_binding2()
3722+
@test_throws ErrorException begin
3723+
@Base.Experimental.force_compile
3724+
(Foreign54607.foo = 1)
3725+
end
3726+
@test_throws ErrorException @eval (GlobalRef(Foreign54607, :gr_assign2)) = 7
3727+
Foreign54607.global_create_binding()
3728+
@test isdefined(Foreign54607, :bar)
3729+
@test isdefined(Foreign54607, :baz)
3730+
@test isdefined(Foreign54607, :compiled_assign)
3731+
@test isdefined(Foreign54607, :gr_assign)
3732+
Foreign54607.bar = 8
3733+
@test Foreign54607.bar == 8
3734+
begin
3735+
@Base.Experimental.force_compile
3736+
Foreign54607.bar = 9
3737+
end
3738+
@test Foreign54607.bar == 9

0 commit comments

Comments
 (0)