Skip to content

Commit 48120f3

Browse files
committed
bpart: Also partition ->deprecated
This repeats the exercise in #57405. This is required for correctness, because the ->deprecated flag also affects `using` resolution (since it makes the tagged binding weaker for `using` purposes). That said, in general our `->deprecated` semantics have been somewhat underspecified with lots of `XXX` comments in the surrounding code. This tries to define the semantics to give a depwarn on *access* (read or write) when: 1. Either the binding itself is deprecated; or 2. The implicit imports pass through a deprecated binding. However, we do not give depwarns on access to bindings that were explicitly imported (although we do give those warnings on the import) - the reasoning being that it's the import that needs to be adjusted not the access. Additionally, this PR moves into the direction of making the depwarn a semantic part of the global access, by adjusting codegen and inference appropriately.
1 parent 0163991 commit 48120f3

File tree

11 files changed

+256
-135
lines changed

11 files changed

+256
-135
lines changed

Compiler/src/Compiler.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ using Core: ABIOverride, Builtin, CodeInstance, IntrinsicFunction, MethodInstanc
5050
using Base
5151
using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospecializeinfer,
5252
BINDING_KIND_GLOBAL, BINDING_KIND_UNDEF_CONST, BINDING_KIND_BACKDATED_CONST, BINDING_KIND_DECLARED,
53+
BINDING_FLAG_DEPWARN,
5354
Base, BitVector, Bottom, Callable, DataTypeFieldDesc,
5455
EffectsOverride, Filter, Generator, IteratorSize, JLOptions, NUM_EFFECTS_OVERRIDES,
5556
OneTo, Ordering, RefValue, SizeUnknown, _NAMEDTUPLE_NAME,

Compiler/src/abstractinterpretation.jl

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2391,7 +2391,7 @@ function abstract_throw_methoderror(interp::AbstractInterpreter, argtypes::Vecto
23912391
return Future(CallMeta(Union{}, exct, EFFECTS_THROWS, NoCallInfo()))
23922392
end
23932393

2394-
const generic_getglobal_effects = Effects(EFFECTS_THROWS, consistent=ALWAYS_FALSE, inaccessiblememonly=ALWAYS_FALSE)
2394+
const generic_getglobal_effects = Effects(EFFECTS_THROWS, effect_free=ALWAYS_FALSE, consistent=ALWAYS_FALSE, inaccessiblememonly=ALWAYS_FALSE) #= effect_free for depwarn =#
23952395
const generic_getglobal_exct = Union{ArgumentError, TypeError, ConcurrencyViolationError, UndefVarError}
23962396
function abstract_eval_getglobal(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, @nospecialize(M), @nospecialize(s))
23972397
= partialorder(typeinf_lattice(interp))
@@ -3519,32 +3519,36 @@ end
35193519

35203520
function abstract_eval_partition_load(interp::AbstractInterpreter, partition::Core.BindingPartition)
35213521
kind = binding_kind(partition)
3522+
isdepwarn = (partition.kind & BINDING_FLAG_DEPWARN) != 0
3523+
local_getglobal_effects = Effects(generic_getglobal_effects, effect_free=isdepwarn ? ALWAYS_FALSE : ALWAYS_TRUE)
35223524
if is_some_guard(kind) || kind == BINDING_KIND_UNDEF_CONST
35233525
if InferenceParams(interp).assume_bindings_static
35243526
return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
35253527
else
35263528
# We do not currently assume an invalidation for guard -> defined transitions
35273529
# return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
3528-
return RTEffects(Any, UndefVarError, generic_getglobal_effects)
3530+
return RTEffects(Any, UndefVarError, local_getglobal_effects)
35293531
end
35303532
end
35313533

35323534
if is_defined_const_binding(kind)
35333535
if kind == BINDING_KIND_BACKDATED_CONST
35343536
# Infer this as guard. We do not want a later const definition to retroactively improve
35353537
# inference results in an earlier world.
3536-
return RTEffects(Any, UndefVarError, generic_getglobal_effects)
3538+
return RTEffects(Any, UndefVarError, local_getglobal_effects)
35373539
end
35383540
rt = Const(partition_restriction(partition))
3539-
return RTEffects(rt, Union{}, Effects(EFFECTS_TOTAL, inaccessiblememonly=is_mutation_free_argtype(rt) ? ALWAYS_TRUE : ALWAYS_FALSE))
3541+
return RTEffects(rt, Union{}, Effects(EFFECTS_TOTAL,
3542+
inaccessiblememonly=is_mutation_free_argtype(rt) ? ALWAYS_TRUE : ALWAYS_FALSE,
3543+
effect_free=isdepwarn ? ALWAYS_FALSE : ALWAYS_TRUE))
35403544
end
35413545

35423546
if kind == BINDING_KIND_DECLARED
35433547
rt = Any
35443548
else
35453549
rt = partition_restriction(partition)
35463550
end
3547-
return RTEffects(rt, UndefVarError, generic_getglobal_effects)
3551+
return RTEffects(rt, UndefVarError, local_getglobal_effects)
35483552
end
35493553

35503554
function abstract_eval_globalref(interp::AbstractInterpreter, g::GlobalRef, saw_latestworld::Bool, sv::AbsIntState)

base/runtime_internals.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,11 @@ const BINDING_KIND_UNDEF_CONST = 0x9
210210
const BINDING_KIND_BACKDATED_CONST = 0xa
211211

212212
const BINDING_FLAG_EXPORTED = 0x10
213+
const BINDING_FLAG_DEPRECATED = 0x20
214+
const BINDING_FLAG_DEPWARN = 0x40
215+
216+
const BINDING_KIND_MASK = 0x0f
217+
const BINDING_FLAG_MASK = 0xf0
213218

214219
is_defined_const_binding(kind::UInt8) = (kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT || kind == BINDING_KIND_BACKDATED_CONST)
215220
is_some_const_binding(kind::UInt8) = (is_defined_const_binding(kind) || kind == BINDING_KIND_UNDEF_CONST)

base/show.jl

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3375,8 +3375,21 @@ function print_partition(io::IO, partition::Core.BindingPartition)
33753375
else
33763376
print(io, max_world)
33773377
end
3378-
if (partition.kind & BINDING_FLAG_EXPORTED) != 0
3379-
print(io, " [exported]")
3378+
if (partition.kind & BINDING_FLAG_MASK) != 0
3379+
first = false
3380+
print(io, " [")
3381+
if (partition.kind & BINDING_FLAG_EXPORTED) != 0
3382+
print(io, "exported")
3383+
end
3384+
if (partition.kind & BINDING_FLAG_DEPRECATED) != 0
3385+
first ? (first = false) : print(io, ",")
3386+
print(io, "deprecated")
3387+
end
3388+
if (partition.kind & BINDING_FLAG_DEPWARN) != 0
3389+
first ? (first = false) : print(io, ",")
3390+
print(io, "depwarn")
3391+
end
3392+
print(io, "]")
33803393
end
33813394
print(io, " - ")
33823395
kind = binding_kind(partition)

src/codegen.cpp

Lines changed: 59 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -907,13 +907,12 @@ static const auto jldeclareglobal_func = new JuliaFunction<>{
907907
{T_pjlvalue, T_pjlvalue, T_prjlvalue, getInt32Ty(C)}, false); },
908908
nullptr,
909909
};
910-
static const auto jlgetbindingorerror_func = new JuliaFunction<>{
911-
XSTR(jl_get_binding_or_error),
910+
static const auto jldepcheck_func = new JuliaFunction<>{
911+
XSTR(jl_binding_deprecation_check),
912912
[](LLVMContext &C) {
913913
auto T_pjlvalue = JuliaType::get_pjlvalue_ty(C);
914-
return FunctionType::get(T_pjlvalue,
915-
{T_pjlvalue, T_pjlvalue}, false);
916-
},
914+
return FunctionType::get(getVoidTy(C),
915+
{T_pjlvalue}, false); },
917916
nullptr,
918917
};
919918
static const auto jlcheckbpwritable_func = new JuliaFunction<>{
@@ -3067,20 +3066,6 @@ static void mallocVisitLine(jl_codectx_t &ctx, StringRef filename, int line, Val
30673066

30683067
// --- constant determination ---
30693068

3070-
static void show_source_loc(jl_codectx_t &ctx, JL_STREAM *out)
3071-
{
3072-
jl_printf(out, "in %s at %s", ctx.name, ctx.file.str().c_str());
3073-
}
3074-
3075-
static void cg_bdw(jl_codectx_t &ctx, jl_sym_t *var, jl_binding_t *b)
3076-
{
3077-
jl_binding_deprecation_warning(ctx.module, var, b);
3078-
if (b->deprecated == 1 && jl_options.depwarn) {
3079-
show_source_loc(ctx, JL_STDERR);
3080-
jl_printf(JL_STDERR, "\n");
3081-
}
3082-
}
3083-
30843069
static jl_value_t *static_apply_type(jl_codectx_t &ctx, ArrayRef<jl_cgval_t> args, size_t nargs)
30853070
{
30863071
assert(nargs > 1);
@@ -3105,6 +3090,12 @@ static jl_value_t *static_apply_type(jl_codectx_t &ctx, ArrayRef<jl_cgval_t> arg
31053090
return result;
31063091
}
31073092

3093+
static void emit_depwarn_check(jl_codectx_t &ctx, jl_binding_t *b)
3094+
{
3095+
Value *bp = julia_binding_gv(ctx, b);
3096+
ctx.builder.CreateCall(prepare_call(jldepcheck_func), { bp });
3097+
}
3098+
31083099
// try to statically evaluate, NULL if not possible. note that this may allocate, and as
31093100
// such the resulting value should not be embedded directly in the generated code.
31103101
static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex)
@@ -3113,9 +3104,13 @@ static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex)
31133104
jl_sym_t *sym = (jl_sym_t*)ex;
31143105
jl_binding_t *bnd = jl_get_module_binding(ctx.module, sym, 0);
31153106
jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world);
3116-
jl_walk_binding_inplace_all(&bnd, &bpart, ctx.min_world, ctx.max_world);
3117-
if (bpart && jl_bkind_is_some_constant(jl_binding_kind(bpart)))
3107+
int possibly_deprecated = 0;
3108+
jl_walk_binding_inplace_all(&bnd, &bpart, &possibly_deprecated, ctx.min_world, ctx.max_world);
3109+
if (bpart && jl_bkind_is_some_constant(jl_binding_kind(bpart))) {
3110+
if (possibly_deprecated)
3111+
emit_depwarn_check(ctx, bnd);
31183112
return bpart->restriction;
3113+
}
31193114
return NULL;
31203115
}
31213116
if (jl_is_slotnumber(ex) || jl_is_argument(ex))
@@ -3138,13 +3133,14 @@ static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex)
31383133
s = jl_globalref_name(ex);
31393134
jl_binding_t *bnd = jl_get_module_binding(jl_globalref_mod(ex), s, 0);
31403135
jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world);
3141-
jl_walk_binding_inplace_all(&bnd, &bpart, ctx.min_world, ctx.max_world);
3136+
int possibly_deprecated = 0;
3137+
jl_walk_binding_inplace_all(&bnd, &bpart, &possibly_deprecated, ctx.min_world, ctx.max_world);
31423138
jl_value_t *v = NULL;
31433139
if (bpart && jl_bkind_is_some_constant(jl_binding_kind(bpart)))
31443140
v = bpart->restriction;
31453141
if (v) {
3146-
if (bnd->deprecated)
3147-
cg_bdw(ctx, s, bnd);
3142+
if (possibly_deprecated)
3143+
emit_depwarn_check(ctx, bnd);
31483144
return v;
31493145
}
31503146
return NULL;
@@ -3165,13 +3161,14 @@ static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex)
31653161
if (s && jl_is_symbol(s)) {
31663162
jl_binding_t *bnd = jl_get_module_binding(m, s, 0);
31673163
jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world);
3168-
jl_walk_binding_inplace_all(&bnd, &bpart, ctx.min_world, ctx.max_world);
3164+
int possibly_deprecated = 0;
3165+
jl_walk_binding_inplace_all(&bnd, &bpart, &possibly_deprecated, ctx.min_world, ctx.max_world);
31693166
jl_value_t *v = NULL;
31703167
if (bpart && jl_bkind_is_some_constant(jl_binding_kind(bpart)))
31713168
v = bpart->restriction;
31723169
if (v) {
3173-
if (bnd->deprecated)
3174-
cg_bdw(ctx, s, bnd);
3170+
if (possibly_deprecated)
3171+
emit_depwarn_check(ctx, bnd);
31753172
return v;
31763173
}
31773174
}
@@ -3417,48 +3414,47 @@ static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *
34173414
if (!bpart) {
34183415
return emit_globalref_runtime(ctx, bnd, mod, name);
34193416
}
3420-
// bpart was updated in place - this will change with full partition
3421-
if (jl_bkind_is_some_guard(jl_binding_kind(bpart))) {
3422-
// Redo the lookup at runtime
3423-
return emit_globalref_runtime(ctx, bnd, mod, name);
3424-
} else {
3425-
while (true) {
3426-
if (!bpart)
3427-
break;
3428-
if (!jl_bkind_is_some_import(jl_binding_kind(bpart)))
3429-
break;
3430-
if (bnd->deprecated) {
3431-
cg_bdw(ctx, name, bnd);
3432-
}
3433-
bnd = (jl_binding_t*)bpart->restriction;
3434-
bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world);
3435-
if (!bpart)
3436-
break;
3437-
}
3438-
if (bpart) {
3439-
enum jl_partition_kind kind = jl_binding_kind(bpart);
3440-
if (jl_bkind_is_some_constant(kind) && kind != BINDING_KIND_BACKDATED_CONST) {
3441-
jl_value_t *constval = bpart->restriction;
3442-
if (!constval) {
3443-
undef_var_error_ifnot(ctx, ConstantInt::get(getInt1Ty(ctx.builder.getContext()), 0), name, (jl_value_t*)mod);
3444-
return jl_cgval_t();
3445-
}
3446-
return mark_julia_const(ctx, constval);
3417+
int possibly_deprecated = 0;
3418+
int saw_explicit = 0;
3419+
while (bpart) {
3420+
if (!saw_explicit && (bpart->kind & BINDING_FLAG_DEPWARN))
3421+
possibly_deprecated = 1;
3422+
enum jl_partition_kind kind = jl_binding_kind(bpart);
3423+
if (!jl_bkind_is_some_import(kind))
3424+
break;
3425+
if (kind != BINDING_KIND_IMPLICIT)
3426+
saw_explicit = 1;
3427+
bnd = (jl_binding_t*)bpart->restriction;
3428+
bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world);
3429+
}
3430+
Value *bp = NULL;
3431+
if (bpart) {
3432+
enum jl_partition_kind kind = jl_binding_kind(bpart);
3433+
if (jl_bkind_is_some_constant(kind) && kind != BINDING_KIND_BACKDATED_CONST) {
3434+
if (possibly_deprecated) {
3435+
bp = julia_binding_gv(ctx, bnd);
3436+
ctx.builder.CreateCall(prepare_call(jldepcheck_func), { bp });
3437+
}
3438+
jl_value_t *constval = bpart->restriction;
3439+
if (!constval) {
3440+
undef_var_error_ifnot(ctx, ConstantInt::get(getInt1Ty(ctx.builder.getContext()), 0), name, (jl_value_t*)mod);
3441+
return jl_cgval_t();
34473442
}
3443+
return mark_julia_const(ctx, constval);
34483444
}
34493445
}
34503446
if (!bpart || jl_binding_kind(bpart) != BINDING_KIND_GLOBAL) {
34513447
return emit_globalref_runtime(ctx, bnd, mod, name);
34523448
}
3453-
Value *bp = julia_binding_gv(ctx, bnd);
3454-
if (bnd->deprecated) {
3455-
cg_bdw(ctx, name, bnd);
3449+
bp = julia_binding_gv(ctx, bnd);
3450+
if (possibly_deprecated) {
3451+
ctx.builder.CreateCall(prepare_call(jldepcheck_func), { bp });
34563452
}
34573453
jl_value_t *ty = bpart->restriction;
3458-
bp = julia_binding_pvalue(ctx, bp);
3454+
Value *bpval = julia_binding_pvalue(ctx, bp);
34593455
if (ty == nullptr)
34603456
ty = (jl_value_t*)jl_any_type;
3461-
return update_julia_type(ctx, emit_checked_var(ctx, bp, name, (jl_value_t*)mod, false, ctx.tbaa().tbaa_binding), ty);
3457+
return update_julia_type(ctx, emit_checked_var(ctx, bpval, name, (jl_value_t*)mod, false, ctx.tbaa().tbaa_binding), ty);
34623458
}
34633459

34643460
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,
@@ -3471,6 +3467,7 @@ static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *s
34713467
Value *bp = julia_binding_gv(ctx, bnd);
34723468
if (bpart) {
34733469
if (jl_binding_kind(bpart) == BINDING_KIND_GLOBAL) {
3470+
int possibly_deprecated = bpart->kind & BINDING_FLAG_DEPWARN;
34743471
jl_value_t *ty = bpart->restriction;
34753472
if (ty != nullptr) {
34763473
const std::string fname = issetglobal ? "setglobal!" : isreplaceglobal ? "replaceglobal!" : isswapglobal ? "swapglobal!" : ismodifyglobal ? "modifyglobal!" : "setglobalonce!";
@@ -3483,6 +3480,9 @@ static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *s
34833480
}
34843481
bool isboxed = true;
34853482
bool maybe_null = jl_atomic_load_relaxed(&bnd->value) == NULL;
3483+
if (possibly_deprecated) {
3484+
ctx.builder.CreateCall(prepare_call(jldepcheck_func), { bp });
3485+
}
34863486
return typed_store(ctx,
34873487
julia_binding_pvalue(ctx, bp),
34883488
rval, cmp, ty,
@@ -10308,7 +10308,6 @@ static void init_jit_functions(void)
1030810308
add_named_global(memcmp_func, &memcmp);
1030910309
add_named_global(jltypeerror_func, &jl_type_error);
1031010310
add_named_global(jlcheckassign_func, &jl_checked_assignment);
10311-
add_named_global(jlgetbindingorerror_func, &jl_get_binding_or_error);
1031210311
add_named_global(jlcheckbpwritable_func, &jl_check_binding_currently_writable);
1031310312
add_named_global(jlboundp_func, &jl_boundp);
1031410313
for (auto it : builtin_func_map())

src/jl_exported_funcs.inc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,6 @@
193193
XX(jl_get_backtrace) \
194194
XX(jl_get_binding) \
195195
XX(jl_get_binding_for_method_def) \
196-
XX(jl_get_binding_or_error) \
197196
XX(jl_get_binding_wr) \
198197
XX(jl_check_binding_currently_writable) \
199198
XX(jl_get_cpu_name) \

src/julia.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -707,8 +707,21 @@ enum jl_partition_kind {
707707
BINDING_KIND_IMPLICIT_RECOMPUTE = 0xb
708708
};
709709

710-
// These are flags that get anded into the above
710+
static const uint8_t BINDING_KIND_MASK = 0x0f;
711+
static const uint8_t BINDING_FLAG_MASK = 0xf0;
712+
713+
//// These are flags that get anded into the above
714+
//
715+
// _EXPORTED: This binding partition is exported. In the world ranges covered by this partitions,
716+
// other modules that `using` this module, may implicit import this binding.
711717
static const uint8_t BINDING_FLAG_EXPORTED = 0x10;
718+
// _DEPRECATED: This binding partition is deprecated. It is considered weak for the purposes of
719+
// implicit import resolution.
720+
static const uint8_t BINDING_FLAG_DEPRECATED = 0x20;
721+
// _DEPWARN: This binding partition will print a deprecation warning on access. Note that _DEPWARN
722+
// implies _DEPRECATED. However, the reverse is not true. Such bindings are usually used for functions,
723+
// where calling the function itself will provide a (better) deprecation warning/error.
724+
static const uint8_t BINDING_FLAG_DEPWARN = 0x40;
712725

713726
typedef struct __attribute__((aligned(8))) _jl_binding_partition_t {
714727
JL_DATA_TYPE
@@ -2054,7 +2067,6 @@ JL_DLLEXPORT jl_value_t *jl_get_module_binding_or_nothing(jl_module_t *m, jl_sym
20542067

20552068
// get binding for reading
20562069
JL_DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var);
2057-
JL_DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var);
20582070
JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var);
20592071
JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var);
20602072
// get binding for assignment

0 commit comments

Comments
 (0)