Skip to content

Commit 5c8e679

Browse files
committed
more predictable global binding resolution
This changes the meaning of `global` from being a directive when used at toplevel, which forces the introduction of a new global when used in certain contexts, to always being just an scope annotation that there should exist a global binding for the given name. fix #18933 fix #17387 (for the syntactic case)
1 parent fc10c8b commit 5c8e679

18 files changed

+279
-216
lines changed

NEWS.md

+7
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ Language changes
3232
* `{ }` expressions now use `braces` and `bracescat` as expression heads instead
3333
of `cell1d` and `cell2d`, and parse similarly to `vect` and `vcat` ([#8470]).
3434

35+
* The `global` keyword now always introduces a new binding when appearing in toplevel (global) scope.
36+
Whereas, previously, embedding it in a block (such as `begin; global sin; nothing; end`) would change its meaning.
37+
Additionally, the new bindings are now created before the statement is executed.
38+
For example, `f() = (global sin = rand(); nothing)` will now reliably shadow the `Base.sin` function,
39+
with a new, undefined `sin` variable. ([#22984]).
40+
41+
3542
Breaking changes
3643
----------------
3744

base/poll.jl

+1-2
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,7 @@ mutable struct _FDWatcher
145145
end
146146
end
147147

148-
global uvfinalize
149-
function uvfinalize(t::_FDWatcher)
148+
function Base.uvfinalize(t::_FDWatcher)
150149
if t.handle != C_NULL
151150
disassociate_julia_struct(t)
152151
ccall(:jl_close_uv, Void, (Ptr{Void},), t.handle)

doc/src/manual/modules.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,8 @@ in other modules can be invoked as `Mod.@mac` or `@Mod.mac`.
214214
The syntax `M.x = y` does not work to assign a global in another module; global assignment is
215215
always module-local.
216216

217-
A variable can be "reserved" for the current module without assigning to it by declaring it as
218-
`global x` at the top level. This can be used to prevent name conflicts for globals initialized
219-
after load time.
217+
A variable name can be "reserved" without assigning to it by declaring it as `global x`.
218+
This prevents name conflicts for globals initialized after load time.
220219

221220
### Module initialization and precompilation
222221

@@ -283,6 +282,7 @@ const foo_data_ptr = Ref{Ptr{Void}}(0)
283282
function __init__()
284283
ccall((:foo_init, :libfoo), Void, ())
285284
foo_data_ptr[] = ccall((:foo_data, :libfoo), Ptr{Void}, ())
285+
nothing
286286
end
287287
```
288288

doc/src/manual/variables-and-scoping.md

+4-18
Original file line numberDiff line numberDiff line change
@@ -174,19 +174,6 @@ julia> x
174174
12
175175
```
176176

177-
Within soft scopes, the *global* keyword is never necessary, although allowed. The only case
178-
when it would change the semantics is (currently) a syntax error:
179-
180-
```jldoctest
181-
julia> let
182-
local j = 2
183-
let
184-
global j = 3
185-
end
186-
end
187-
ERROR: syntax: `global j`: j is local variable in the enclosing scope
188-
```
189-
190177
### Hard Local Scope
191178

192179
Hard local scopes are introduced by function definitions (in all their forms), struct type definition blocks,
@@ -336,8 +323,7 @@ constructing [closures](https://en.wikipedia.org/wiki/Closure_%28computer_progra
336323
have a private state, for instance the `state` variable in the following example:
337324

338325
```jldoctest
339-
julia> let
340-
state = 0
326+
julia> let state = 0
341327
global counter
342328
counter() = state += 1
343329
end;
@@ -483,13 +469,13 @@ julia> const e = 2.71828182845904523536;
483469
julia> const pi = 3.14159265358979323846;
484470
```
485471

486-
The `const` declaration is allowed on both global and local variables, but is especially useful
487-
for globals. It is difficult for the compiler to optimize code involving global variables, since
472+
The `const` declaration should only be used in global scope on globals.
473+
It is difficult for the compiler to optimize code involving global variables, since
488474
their values (or even their types) might change at almost any time. If a global variable will
489475
not change, adding a `const` declaration solves this performance problem.
490476

491477
Local constants are quite different. The compiler is able to determine automatically when a local
492-
variable is constant, so local constant declarations are not necessary for performance purposes.
478+
variable is constant, so local constant declarations are not necessary, and are currently just ignored.
493479

494480
Special top-level assignments, such as those performed by the `function` and `struct` keywords,
495481
are constant by default.

src/ccall.cpp

+9-8
Original file line numberDiff line numberDiff line change
@@ -475,13 +475,14 @@ static Value *llvm_type_rewrite(
475475
static Value *runtime_apply_type(jl_codectx_t &ctx, jl_value_t *ty, jl_unionall_t *unionall)
476476
{
477477
// box if concrete type was not statically known
478-
Value *args[3];
479-
args[0] = literal_pointer_val(ctx, ty);
480-
args[1] = literal_pointer_val(ctx, (jl_value_t*)ctx.linfo->def.method->sig);
481-
args[2] = ctx.builder.CreateInBoundsGEP(
482-
T_prjlvalue,
483-
ctx.spvals_ptr,
484-
ConstantInt::get(T_size, sizeof(jl_svec_t) / sizeof(jl_value_t*)));
478+
Value *args[] = {
479+
literal_pointer_val(ctx, ty),
480+
literal_pointer_val(ctx, (jl_value_t*)ctx.linfo->def.method->sig),
481+
ctx.builder.CreateInBoundsGEP(
482+
T_prjlvalue,
483+
ctx.spvals_ptr,
484+
ConstantInt::get(T_size, sizeof(jl_svec_t) / sizeof(jl_value_t*)))
485+
};
485486
return ctx.builder.CreateCall(prepare_call(jlapplytype_func), makeArrayRef(args));
486487
}
487488

@@ -1499,7 +1500,7 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs)
14991500
else {
15001501
Value *notany = ctx.builder.CreateICmpNE(
15011502
boxed(ctx, runtime_sp, false),
1502-
literal_pointer_val(ctx, (jl_value_t*)jl_any_type));
1503+
maybe_decay_untracked(literal_pointer_val(ctx, (jl_value_t*)jl_any_type)));
15031504
error_unless(ctx, notany, "ccall: return type Ref{Any} is invalid. use Ptr{Any} instead.");
15041505
always_error = false;
15051506
}

src/cgutils.cpp

+40-40
Original file line numberDiff line numberDiff line change
@@ -247,15 +247,15 @@ static Value *emit_pointer_from_objref(jl_codectx_t &ctx, Value *V)
247247

248248
// --- emitting pointers directly into code ---
249249

250-
static Constant *literal_static_pointer_val(jl_codectx_t &ctx, const void *p, Type *t)
250+
static Constant *literal_static_pointer_val(jl_codectx_t &ctx, const void *p, Type *T = T_pjlvalue)
251251
{
252252
// this function will emit a static pointer into the generated code
253253
// the generated code will only be valid during the current session,
254254
// and thus, this should typically be avoided in new API's
255255
#if defined(_P64)
256-
return ConstantExpr::getPointerBitCastOrAddrSpaceCast(ConstantExpr::getIntToPtr(ConstantInt::get(T_int64, (uint64_t)p), T_pjlvalue), t);
256+
return ConstantExpr::getIntToPtr(ConstantInt::get(T_int64, (uint64_t)p), T);
257257
#else
258-
return ConstantExpr::getPointerBitCastOrAddrSpaceCast(ConstantExpr::getIntToPtr(ConstantInt::get(T_int32, (uint32_t)p), T_pjlvalue), t);
258+
return ConstantExpr::getIntToPtr(ConstantInt::get(T_int32, (uint32_t)p), T);
259259
#endif
260260
}
261261

@@ -304,47 +304,47 @@ static Value *literal_pointer_val_slot(jl_codectx_t &ctx, jl_value_t *p)
304304
Module *M = jl_Module;
305305
GlobalVariable *gv = new GlobalVariable(
306306
*M, T_pjlvalue, true, GlobalVariable::PrivateLinkage,
307-
literal_static_pointer_val(ctx, p, T_pjlvalue));
307+
literal_static_pointer_val(ctx, p));
308308
gv->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
309309
return gv;
310310
}
311311
if (GlobalVariable *gv = julia_const_gv(p)) {
312312
// if this is a known object, use the existing GlobalValue
313-
return maybe_decay_untracked(prepare_global(gv));
313+
return prepare_global(gv);
314314
}
315315
if (jl_is_datatype(p)) {
316316
jl_datatype_t *addr = (jl_datatype_t*)p;
317317
// DataTypes are prefixed with a +
318-
return maybe_decay_untracked(julia_pgv(ctx, "+", addr->name->name, addr->name->module, p));
318+
return julia_pgv(ctx, "+", addr->name->name, addr->name->module, p);
319319
}
320320
if (jl_is_method(p)) {
321321
jl_method_t *m = (jl_method_t*)p;
322322
// functions are prefixed with a -
323-
return maybe_decay_untracked(julia_pgv(ctx, "-", m->name, m->module, p));
323+
return julia_pgv(ctx, "-", m->name, m->module, p);
324324
}
325325
if (jl_is_method_instance(p)) {
326326
jl_method_instance_t *linfo = (jl_method_instance_t*)p;
327327
// Type-inferred functions are also prefixed with a -
328328
if (jl_is_method(linfo->def.method))
329-
return maybe_decay_untracked(julia_pgv(ctx, "-", linfo->def.method->name, linfo->def.method->module, p));
329+
return julia_pgv(ctx, "-", linfo->def.method->name, linfo->def.method->module, p);
330330
}
331331
if (jl_is_symbol(p)) {
332332
jl_sym_t *addr = (jl_sym_t*)p;
333333
// Symbols are prefixed with jl_sym#
334-
return maybe_decay_untracked(julia_pgv(ctx, "jl_sym#", addr, NULL, p));
334+
return julia_pgv(ctx, "jl_sym#", addr, NULL, p);
335335
}
336336
// something else gets just a generic name
337-
return maybe_decay_untracked(julia_pgv(ctx, "jl_global#", p));
337+
return julia_pgv(ctx, "jl_global#", p);
338338
}
339339

340340
static Value *literal_pointer_val(jl_codectx_t &ctx, jl_value_t *p)
341341
{
342342
if (p == NULL)
343343
return V_null;
344344
if (!imaging_mode)
345-
return literal_static_pointer_val(ctx, p, T_prjlvalue);
345+
return literal_static_pointer_val(ctx, p);
346346
Value *pgv = literal_pointer_val_slot(ctx, p);
347-
return tbaa_decorate(tbaa_const, ctx.builder.CreateLoad(pgv));
347+
return tbaa_decorate(tbaa_const, ctx.builder.CreateLoad(T_pjlvalue, pgv));
348348
}
349349

350350
static Value *literal_pointer_val(jl_codectx_t &ctx, jl_binding_t *p)
@@ -353,10 +353,10 @@ static Value *literal_pointer_val(jl_codectx_t &ctx, jl_binding_t *p)
353353
if (p == NULL)
354354
return V_null;
355355
if (!imaging_mode)
356-
return literal_static_pointer_val(ctx, p, T_pjlvalue);
356+
return literal_static_pointer_val(ctx, p);
357357
// bindings are prefixed with jl_bnd#
358358
Value *pgv = julia_pgv(ctx, "jl_bnd#", p->name, p->owner, p);
359-
return tbaa_decorate(tbaa_const, ctx.builder.CreateLoad(pgv));
359+
return tbaa_decorate(tbaa_const, ctx.builder.CreateLoad(T_pjlvalue, pgv));
360360
}
361361

362362
// bitcast a value, but preserve its address space when dealing with pointer types
@@ -389,10 +389,10 @@ static Value *julia_binding_gv(jl_codectx_t &ctx, jl_binding_t *b)
389389
if (imaging_mode)
390390
bv = emit_bitcast(ctx,
391391
tbaa_decorate(tbaa_const,
392-
ctx.builder.CreateLoad(julia_pgv(ctx, "*", b->name, b->owner, b))),
392+
ctx.builder.CreateLoad(T_pjlvalue, julia_pgv(ctx, "*", b->name, b->owner, b))),
393393
T_pprjlvalue);
394394
else
395-
bv = literal_static_pointer_val(ctx, b, T_pprjlvalue);
395+
bv = ConstantExpr::getBitCast(literal_static_pointer_val(ctx, b), T_pprjlvalue);
396396
return julia_binding_gv(ctx, bv);
397397
}
398398

@@ -659,21 +659,21 @@ static Value *emit_nthptr(jl_codectx_t &ctx, Value *v, ssize_t n, MDNode *tbaa)
659659
{
660660
// p = (jl_value_t**)v; p[n]
661661
Value *vptr = emit_nthptr_addr(ctx, v, n);
662-
return tbaa_decorate(tbaa, ctx.builder.CreateLoad(vptr, false));
662+
return tbaa_decorate(tbaa, ctx.builder.CreateLoad(T_prjlvalue, vptr));
663663
}
664664

665665
static Value *emit_nthptr_recast(jl_codectx_t &ctx, Value *v, Value *idx, MDNode *tbaa, Type *ptype, bool gctracked = true)
666666
{
667667
// p = (jl_value_t**)v; *(ptype)&p[n]
668668
Value *vptr = emit_nthptr_addr(ctx, v, idx, gctracked);
669-
return tbaa_decorate(tbaa, ctx.builder.CreateLoad(emit_bitcast(ctx, vptr, ptype), false));
669+
return tbaa_decorate(tbaa, ctx.builder.CreateLoad(emit_bitcast(ctx, vptr, ptype)));
670670
}
671671

672672
static Value *emit_nthptr_recast(jl_codectx_t &ctx, Value *v, ssize_t n, MDNode *tbaa, Type *ptype, bool gctracked = true)
673673
{
674674
// p = (jl_value_t**)v; *(ptype)&p[n]
675675
Value *vptr = emit_nthptr_addr(ctx, v, n, gctracked);
676-
return tbaa_decorate(tbaa, ctx.builder.CreateLoad(emit_bitcast(ctx, vptr, ptype), false));
676+
return tbaa_decorate(tbaa, ctx.builder.CreateLoad(emit_bitcast(ctx, vptr, ptype)));
677677
}
678678

679679
static Value *emit_typeptr_addr(jl_codectx_t &ctx, Value *p)
@@ -703,7 +703,7 @@ static Value *emit_typeof(jl_codectx_t &ctx, Value *tt)
703703
// is fine however, since leaf types are not GCed at the moment. Should
704704
// that ever change, this may have to go through a special intrinsic.
705705
Value *addr = emit_bitcast(ctx, emit_typeptr_addr(ctx, tt), T_ppjlvalue);
706-
tt = tbaa_decorate(tbaa_tag, ctx.builder.CreateLoad(addr));
706+
tt = tbaa_decorate(tbaa_tag, ctx.builder.CreateLoad(T_pjlvalue, addr));
707707
return maybe_decay_untracked(mask_gc_bits(ctx, tt));
708708
}
709709

@@ -725,7 +725,7 @@ static jl_cgval_t emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p)
725725
p.typ,
726726
counter);
727727
if (allunboxed)
728-
pdatatype = Constant::getNullValue(T_ppjlvalue);
728+
pdatatype = decay_derived(Constant::getNullValue(T_ppjlvalue));
729729
else {
730730
// See note above in emit_typeof(Value*), we can't tell the system
731731
// about this until we've cleared the GC bits.
@@ -736,18 +736,16 @@ static jl_cgval_t emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p)
736736
[&](unsigned idx, jl_datatype_t *jt) {
737737
Value *cmp = ctx.builder.CreateICmpEQ(tindex, ConstantInt::get(T_int8, idx));
738738
pdatatype = ctx.builder.CreateSelect(cmp,
739-
decay_derived(emit_bitcast(ctx, literal_pointer_val_slot(ctx, (jl_value_t*)jt), T_ppjlvalue)),
740-
decay_derived(pdatatype));
739+
decay_derived(literal_pointer_val_slot(ctx, (jl_value_t*)jt)),
740+
pdatatype);
741741
},
742742
p.typ,
743743
counter);
744-
Value *datatype;
745-
if (allunboxed) {
746-
datatype = tbaa_decorate(tbaa_const, ctx.builder.CreateLoad(maybe_decay_untracked(pdatatype)));
747-
}
748-
else {
749-
datatype = maybe_decay_untracked(mask_gc_bits(ctx, tbaa_decorate(tbaa_tag, ctx.builder.CreateLoad(pdatatype))));
750-
}
744+
Value *datatype = tbaa_decorate(allunboxed ? tbaa_const : tbaa_tag,
745+
ctx.builder.CreateLoad(T_pjlvalue, pdatatype));
746+
if (!allunboxed)
747+
datatype = mask_gc_bits(ctx, datatype);
748+
datatype = maybe_decay_untracked(datatype);
751749
return mark_julia_type(ctx, datatype, true, jl_datatype_type, /*needsroot*/false);
752750
}
753751
jl_value_t *aty = p.typ;
@@ -988,7 +986,7 @@ static void emit_type_error(jl_codectx_t &ctx, const jl_cgval_t &x, Value *type,
988986
Value *msg_val = stringConstPtr(ctx.builder, msg);
989987
ctx.builder.CreateCall(prepare_call(jltypeerror_func),
990988
{ fname_val, msg_val,
991-
type, mark_callee_rooted(boxed(ctx, x, false))});
989+
maybe_decay_untracked(type), mark_callee_rooted(boxed(ctx, x, false))});
992990
}
993991

994992
static std::pair<Value*, bool> emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x, jl_value_t *type, const std::string *msg)
@@ -1013,7 +1011,7 @@ static std::pair<Value*, bool> emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x,
10131011
// intersection with Type needs to be handled specially
10141012
if (jl_has_intersect_type_not_kind(type)) {
10151013
Value *vx = maybe_decay_untracked(boxed(ctx, x));
1016-
Value *vtyp = literal_pointer_val(ctx, type);
1014+
Value *vtyp = maybe_decay_untracked(literal_pointer_val(ctx, type));
10171015
if (msg && *msg == "typeassert") {
10181016
ctx.builder.CreateCall(prepare_call(jltypeassert_func), { vx, vtyp });
10191017
return std::make_pair(ConstantInt::get(T_int1, 1), true);
@@ -1053,11 +1051,10 @@ static std::pair<Value*, bool> emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x,
10531051
maybe_decay_untracked(literal_pointer_val(ctx, type))), false);
10541052
}
10551053
// everything else can be handled via subtype tests
1056-
Value *vxt = maybe_decay_untracked(emit_typeof_boxed(ctx, x));
10571054
return std::make_pair(ctx.builder.CreateICmpNE(
10581055
ctx.builder.CreateCall(prepare_call(jlsubtype_func),
1059-
{ vxt,
1060-
literal_pointer_val(ctx, type) }),
1056+
{ maybe_decay_untracked(emit_typeof_boxed(ctx, x)),
1057+
maybe_decay_untracked(literal_pointer_val(ctx, type)) }),
10611058
ConstantInt::get(T_int32, 0)), false);
10621059
}
10631060

@@ -1130,9 +1127,9 @@ static Value *emit_bounds_check(jl_codectx_t &ctx, const jl_cgval_t &ainfo, jl_v
11301127
a = tempSpace;
11311128
}
11321129
ctx.builder.CreateCall(prepare_call(jluboundserror_func), {
1133-
emit_bitcast(ctx, decay_derived(a), T_pint8),
1134-
literal_pointer_val(ctx, ty),
1135-
i });
1130+
emit_bitcast(ctx, decay_derived(a), T_pint8),
1131+
literal_pointer_val(ctx, ty),
1132+
i });
11361133
}
11371134
ctx.builder.CreateUnreachable();
11381135
ctx.f->getBasicBlockList().push_back(passBB);
@@ -1241,7 +1238,7 @@ static void typed_store(jl_codectx_t &ctx,
12411238
static Value *julia_bool(jl_codectx_t &ctx, Value *cond)
12421239
{
12431240
return ctx.builder.CreateSelect(cond, literal_pointer_val(ctx, jl_true),
1244-
literal_pointer_val(ctx, jl_false));
1241+
literal_pointer_val(ctx, jl_false));
12451242
}
12461243

12471244
// --- accessing the representations of built-in data types ---
@@ -1964,7 +1961,7 @@ static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &vinfo, bool gcrooted)
19641961
// We have an undef value on a (hopefully) dead branch
19651962
return UndefValue::get(T_prjlvalue);
19661963
if (vinfo.constant)
1967-
return literal_pointer_val(ctx, vinfo.constant);
1964+
return maybe_decay_untracked(literal_pointer_val(ctx, vinfo.constant));
19681965
if (vinfo.isboxed) {
19691966
assert(vinfo.V && "Missing value for box.");
19701967
// We're guaranteed here that Load(.gcroot) == .V, because we have determined
@@ -1987,6 +1984,9 @@ static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &vinfo, bool gcrooted)
19871984
box = emit_allocobj(ctx, jl_datatype_size(jt), literal_pointer_val(ctx, (jl_value_t*)jt));
19881985
init_bits_cgval(ctx, box, vinfo, jl_is_mutable(jt) ? tbaa_mutab : tbaa_immut);
19891986
}
1987+
else {
1988+
box = maybe_decay_untracked(box);
1989+
}
19901990
}
19911991
if (gcrooted) {
19921992
// make a gcroot for the new box

0 commit comments

Comments
 (0)