Skip to content

Commit 9874d82

Browse files
KenoKristofferC
authored and
KristofferC
committed
Don't let setglobal! implicitly create bindings (#54678)
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 (cherry picked from commit b7e7232)
1 parent 193fee8 commit 9874d82

File tree

12 files changed

+96
-33
lines changed

12 files changed

+96
-33
lines changed

base/docs/basedocs.jl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2490,12 +2490,17 @@ cases.
24902490
See also [`setproperty!`](@ref Base.setproperty!) and [`getglobal`](@ref)
24912491
24922492
# Examples
2493-
```jldoctest
2494-
julia> module M end;
2493+
```jldoctest; filter = r"Stacktrace:(\\n \\[[0-9]+\\].*)*"
2494+
julia> module M; global a; end;
24952495
24962496
julia> M.a # same as `getglobal(M, :a)`
24972497
ERROR: UndefVarError: `a` not defined in `M`
2498-
Suggestion: check for spelling errors or missing imports.
2498+
Suggestion: add an appropriate import or assignment. This global was declared but not assigned.
2499+
Stacktrace:
2500+
[1] getproperty(x::Module, f::Symbol)
2501+
@ Base ./Base.jl:42
2502+
[2] top-level scope
2503+
@ none:1
24992504
25002505
julia> setglobal!(M, :a, 1)
25012506
1

doc/src/manual/embedding.md

Lines changed: 1 addition & 1 deletion
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

Lines changed: 6 additions & 6 deletions
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

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ static const auto jlgetbindingwrorerror_func = new JuliaFunction<>{
940940
[](LLVMContext &C) {
941941
auto T_pjlvalue = JuliaType::get_pjlvalue_ty(C);
942942
return FunctionType::get(T_pjlvalue,
943-
{T_pjlvalue, T_pjlvalue}, false);
943+
{T_pjlvalue, T_pjlvalue, getInt32Ty(C)}, false);
944944
},
945945
nullptr,
946946
};
@@ -2087,7 +2087,7 @@ static Type *julia_type_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed
20872087
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);
20882088
static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval = -1);
20892089
static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t *s,
2090-
jl_binding_t **pbnd, bool assign);
2090+
jl_binding_t **pbnd, bool assign, bool alloc);
20912091
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);
20922092
static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i);
20932093
static Value *emit_condition(jl_codectx_t &ctx, const jl_cgval_t &condV, const Twine &msg);
@@ -3176,7 +3176,7 @@ static jl_value_t *jl_ensure_rooted(jl_codectx_t &ctx, jl_value_t *val)
31763176
static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *name, AtomicOrdering order)
31773177
{
31783178
jl_binding_t *bnd = NULL;
3179-
Value *bp = global_binding_pointer(ctx, mod, name, &bnd, false);
3179+
Value *bp = global_binding_pointer(ctx, mod, name, &bnd, false, false);
31803180
if (bp == NULL)
31813181
return jl_cgval_t();
31823182
bp = julia_binding_pvalue(ctx, bp);
@@ -3195,10 +3195,10 @@ static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *
31953195
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,
31963196
AtomicOrdering Order, AtomicOrdering FailOrder,
31973197
bool issetglobal, bool isreplaceglobal, bool isswapglobal, bool ismodifyglobal, bool issetglobalonce,
3198-
const jl_cgval_t *modifyop)
3198+
const jl_cgval_t *modifyop, bool alloc)
31993199
{
32003200
jl_binding_t *bnd = NULL;
3201-
Value *bp = global_binding_pointer(ctx, mod, sym, &bnd, true);
3201+
Value *bp = global_binding_pointer(ctx, mod, sym, &bnd, true, alloc);
32023202
if (bp == NULL)
32033203
return jl_cgval_t();
32043204
if (bnd && !bnd->constp) {
@@ -3608,7 +3608,8 @@ static bool emit_f_opglobal(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
36083608
isswapglobal,
36093609
ismodifyglobal,
36103610
issetglobalonce,
3611-
modifyop);
3611+
modifyop,
3612+
false);
36123613
return true;
36133614
}
36143615
}
@@ -5289,7 +5290,7 @@ static void emit_hasnofield_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_sym_t *
52895290
// if the reference currently bound or assign == true,
52905291
// pbnd will also be assigned with the binding address
52915292
static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t *s,
5292-
jl_binding_t **pbnd, bool assign)
5293+
jl_binding_t **pbnd, bool assign, bool alloc)
52935294
{
52945295
jl_binding_t *b = jl_get_module_binding(m, s, 1);
52955296
if (assign) {
@@ -5319,9 +5320,17 @@ static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t
53195320
ctx.builder.CreateCondBr(iscached, have_val, not_found);
53205321
not_found->insertInto(ctx.f);
53215322
ctx.builder.SetInsertPoint(not_found);
5322-
Value *bval = ctx.builder.CreateCall(prepare_call(assign ? jlgetbindingwrorerror_func : jlgetbindingorerror_func),
5323-
{ literal_pointer_val(ctx, (jl_value_t*)m),
5324-
literal_pointer_val(ctx, (jl_value_t*)s) });
5323+
Value *bval = nullptr;
5324+
if (assign) {
5325+
bval = ctx.builder.CreateCall(prepare_call(jlgetbindingwrorerror_func),
5326+
{ literal_pointer_val(ctx, (jl_value_t*)m),
5327+
literal_pointer_val(ctx, (jl_value_t*)s),
5328+
ConstantInt::get(getInt32Ty(ctx.builder.getContext()), alloc)});
5329+
} else {
5330+
bval = ctx.builder.CreateCall(prepare_call(jlgetbindingorerror_func),
5331+
{ literal_pointer_val(ctx, (jl_value_t*)m),
5332+
literal_pointer_val(ctx, (jl_value_t*)s)});
5333+
}
53255334
setName(ctx.emission_context, bval, jl_symbol_name(m->name) + StringRef(".") + jl_symbol_name(s) + ".found");
53265335
ctx.builder.CreateAlignedStore(bval, bindinggv, Align(sizeof(void*)))->setOrdering(AtomicOrdering::Release);
53275336
ctx.builder.CreateBr(have_val);
@@ -5338,7 +5347,8 @@ static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t
53385347
// this will fail at runtime, so defer to the runtime to create the error
53395348
ctx.builder.CreateCall(prepare_call(jlgetbindingwrorerror_func),
53405349
{ literal_pointer_val(ctx, (jl_value_t*)m),
5341-
literal_pointer_val(ctx, (jl_value_t*)s) });
5350+
literal_pointer_val(ctx, (jl_value_t*)s),
5351+
ConstantInt::get(getInt32Ty(ctx.builder.getContext()), alloc) });
53425352
CreateTrap(ctx.builder);
53435353
return NULL;
53445354
}
@@ -5833,17 +5843,20 @@ static void emit_assignment(jl_codectx_t &ctx, jl_value_t *l, jl_value_t *r, ssi
58335843

58345844
jl_module_t *mod;
58355845
jl_sym_t *sym;
5846+
bool toplevel = jl_is_module(ctx.linfo->def.value);
5847+
bool alloc = toplevel;
58365848
if (jl_is_symbol(l)) {
58375849
mod = ctx.module;
58385850
sym = (jl_sym_t*)l;
58395851
}
58405852
else {
58415853
assert(jl_is_globalref(l));
5854+
alloc &= jl_globalref_mod(l) == ctx.module;
58425855
mod = jl_globalref_mod(l);
58435856
sym = jl_globalref_name(l);
58445857
}
58455858
emit_globalop(ctx, mod, sym, rval_info, jl_cgval_t(), AtomicOrdering::Release, AtomicOrdering::NotAtomic,
5846-
true, false, false, false, false, nullptr);
5859+
true, false, false, false, false, nullptr, alloc);
58475860
// Global variable. Does not need debug info because the debugger knows about
58485861
// its memory location.
58495862
}
@@ -6288,7 +6301,7 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_
62886301
}
62896302
if (jl_is_symbol(sym)) {
62906303
jl_binding_t *bnd = NULL;
6291-
Value *bp = global_binding_pointer(ctx, mod, sym, &bnd, true);
6304+
Value *bp = global_binding_pointer(ctx, mod, sym, &bnd, true, true);
62926305
if (bp)
62936306
ctx.builder.CreateCall(prepare_call(jldeclareconst_func),
62946307
{ bp, literal_pointer_val(ctx, (jl_value_t*)mod), literal_pointer_val(ctx, (jl_value_t*)sym) });

src/interpreter.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,17 +568,21 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip,
568568
else {
569569
jl_module_t *modu;
570570
jl_sym_t *sym;
571+
// Plain assignment is allowed to create bindings at
572+
// toplevel and only for the current module
573+
int alloc = toplevel;
571574
if (jl_is_globalref(lhs)) {
572575
modu = jl_globalref_mod(lhs);
573576
sym = jl_globalref_name(lhs);
577+
alloc &= modu == s->module;
574578
}
575579
else {
576580
assert(jl_is_symbol(lhs));
577581
modu = s->module;
578582
sym = (jl_sym_t*)lhs;
579583
}
580584
JL_GC_PUSH1(&rhs);
581-
jl_binding_t *b = jl_get_binding_wr(modu, sym);
585+
jl_binding_t *b = jl_get_binding_wr(modu, sym, alloc);
582586
jl_checked_assignment(b, modu, sym, rhs);
583587
JL_GC_POP();
584588
}

src/julia-syntax.scm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4232,6 +4232,7 @@ f(x) = yt(x)
42324232
(put! globals ref #t)
42334233
`(block
42344234
(toplevel-only set_binding_type! ,(cadr e))
4235+
(global ,ref)
42354236
(call (core set_binding_type!) ,(cadr ref) (inert ,(caddr ref)) ,(caddr e))))
42364237
`(call (core typeassert) ,@(cdr e))))
42374238
fname lam namemap defined toplevel interp opaq globals locals))))

src/julia.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1913,7 +1913,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var
19131913
JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var);
19141914
JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var);
19151915
// get binding for assignment
1916-
JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var);
1916+
JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int alloc);
19171917
JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var);
19181918
JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var);
19191919
JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var);

src/module.c

Lines changed: 6 additions & 3 deletions
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)
@@ -784,7 +787,7 @@ JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m, jl_sym_t *var)
784787

785788
JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT)
786789
{
787-
jl_binding_t *bp = jl_get_binding_wr(m, var);
790+
jl_binding_t *bp = jl_get_binding_wr(m, var, 0);
788791
jl_checked_assignment(bp, m, var, val);
789792
}
790793

src/toplevel.c

Lines changed: 4 additions & 4 deletions
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
@@ -622,7 +622,7 @@ static void import_module(jl_module_t *JL_NONNULL m, jl_module_t *import, jl_sym
622622
jl_symbol_name(name), jl_symbol_name(m->name));
623623
}
624624
else {
625-
b = jl_get_binding_wr(m, name);
625+
b = jl_get_binding_wr(m, name, 1);
626626
}
627627
jl_declare_constant(b, m, name);
628628
jl_checked_assignment(b, m, name, (jl_value_t*)import);
@@ -874,7 +874,7 @@ jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_value_t *e, int
874874
gm = m;
875875
gs = (jl_sym_t*)arg;
876876
}
877-
jl_binding_t *b = jl_get_binding_wr(gm, gs);
877+
jl_binding_t *b = jl_get_binding_wr(gm, gs, 1);
878878
jl_declare_constant(b, gm, gs);
879879
JL_GC_POP();
880880
return jl_nothing;

test/core.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8135,6 +8135,7 @@ end
81358135
@test_broken Int isa Union{Union, Type{Union{Int,T1}} where {T1}}
81368136

81378137
let M = @__MODULE__
8138+
Core.eval(M, :(global a_typed_global))
81388139
@test Core.set_binding_type!(M, :a_typed_global, Tuple{Union{Integer,Nothing}}) === nothing
81398140
@test Core.get_binding_type(M, :a_typed_global) === Tuple{Union{Integer,Nothing}}
81408141
@test Core.set_binding_type!(M, :a_typed_global, Tuple{Union{Integer,Nothing}}) === nothing

test/precompile.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1045,7 +1045,6 @@ precompile_test_harness("code caching") do dir
10451045
@test mi.specTypes.parameters[end] === Integer ? !hv : hv
10461046
end
10471047

1048-
setglobal!(Main, :inval, invalidations)
10491048
idxs = findall(==("verify_methods"), invalidations)
10501049
idxsbits = filter(idxs) do i
10511050
mi = invalidations[i-1]

test/syntax.jl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3653,3 +3653,40 @@ end
36533653
@test f54701() == 3
36543654
@test !@isdefined(a54701)
36553655
@test !@isdefined(b54701)
3656+
3657+
# Issue #54607 - binding creation in foreign modules should not be permitted
3658+
module Foreign54607
3659+
# Syntactic, not dynamic
3660+
try_to_create_binding1() = (Foreign54607.foo = 2)
3661+
@eval try_to_create_binding2() = ($(GlobalRef(Foreign54607, :foo)) = 2)
3662+
function global_create_binding()
3663+
global bar
3664+
bar = 3
3665+
end
3666+
baz = 4
3667+
begin;
3668+
@Base.Experimental.force_compile
3669+
compiled_assign = 5
3670+
end
3671+
@eval $(GlobalRef(Foreign54607, :gr_assign)) = 6
3672+
end
3673+
@test_throws ErrorException (Foreign54607.foo = 1)
3674+
@test_throws ErrorException Foreign54607.try_to_create_binding1()
3675+
@test_throws ErrorException Foreign54607.try_to_create_binding2()
3676+
@test_throws ErrorException begin
3677+
@Base.Experimental.force_compile
3678+
(Foreign54607.foo = 1)
3679+
end
3680+
@test_throws ErrorException @eval (GlobalRef(Foreign54607, :gr_assign2)) = 7
3681+
Foreign54607.global_create_binding()
3682+
@test isdefined(Foreign54607, :bar)
3683+
@test isdefined(Foreign54607, :baz)
3684+
@test isdefined(Foreign54607, :compiled_assign)
3685+
@test isdefined(Foreign54607, :gr_assign)
3686+
Foreign54607.bar = 8
3687+
@test Foreign54607.bar == 8
3688+
begin
3689+
@Base.Experimental.force_compile
3690+
Foreign54607.bar = 9
3691+
end
3692+
@test Foreign54607.bar == 9

0 commit comments

Comments
 (0)