Skip to content

Commit 24ac6a2

Browse files
committed
Auto merge of rust-lang#102704 - Dylan-DPC:rollup-66ff8sm, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - rust-lang#100986 (Stop suggesting adding generic args for turbofish) - rust-lang#101061 (panic-on-uninit: adjust checks to 0x01-filling) - rust-lang#102440 (Only export `__tls_*` on wasm32-unknown-unknown.) - rust-lang#102496 (Suggest `.into()` when all other coercion suggestions fail) - rust-lang#102699 (Fix hamburger button color) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 8c71b67 + 4c644cd commit 24ac6a2

28 files changed

+666
-342
lines changed

compiler/rustc_codegen_ssa/src/back/linker.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -1180,16 +1180,19 @@ impl<'a> WasmLd<'a> {
11801180
// sharing memory and instantiating the module multiple times. As a
11811181
// result if it were exported then we'd just have no sharing.
11821182
//
1183-
// * `--export=*tls*` - when `#[thread_local]` symbols are used these
1184-
// symbols are how the TLS segments are initialized and configured.
1183+
// On wasm32-unknown-unknown, we also export symbols for glue code to use:
1184+
// * `--export=*tls*` - when `#[thread_local]` symbols are used these
1185+
// symbols are how the TLS segments are initialized and configured.
11851186
if sess.target_features.contains(&sym::atomics) {
11861187
cmd.arg("--shared-memory");
11871188
cmd.arg("--max-memory=1073741824");
11881189
cmd.arg("--import-memory");
1189-
cmd.arg("--export=__wasm_init_tls");
1190-
cmd.arg("--export=__tls_size");
1191-
cmd.arg("--export=__tls_align");
1192-
cmd.arg("--export=__tls_base");
1190+
if sess.target.os == "unknown" {
1191+
cmd.arg("--export=__wasm_init_tls");
1192+
cmd.arg("--export=__tls_size");
1193+
cmd.arg("--export=__tls_align");
1194+
cmd.arg("--export=__tls_base");
1195+
}
11931196
}
11941197
WasmLd { cmd, sess }
11951198
}

compiler/rustc_const_eval/src/lib.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ extern crate rustc_middle;
3232
pub mod const_eval;
3333
mod errors;
3434
pub mod interpret;
35-
mod might_permit_raw_init;
3635
pub mod transform;
3736
pub mod util;
3837

@@ -61,7 +60,6 @@ pub fn provide(providers: &mut Providers) {
6160
const_eval::deref_mir_constant(tcx, param_env, value)
6261
};
6362
providers.permits_uninit_init =
64-
|tcx, ty| might_permit_raw_init::might_permit_raw_init(tcx, ty, InitKind::Uninit);
65-
providers.permits_zero_init =
66-
|tcx, ty| might_permit_raw_init::might_permit_raw_init(tcx, ty, InitKind::Zero);
63+
|tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::UninitMitigated0x01Fill);
64+
providers.permits_zero_init = |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::Zero);
6765
}

compiler/rustc_const_eval/src/might_permit_raw_init.rs

-44
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
2+
use rustc_middle::ty::{ParamEnv, TyCtxt};
3+
use rustc_session::Limit;
4+
use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
5+
6+
use crate::const_eval::CompileTimeInterpreter;
7+
use crate::interpret::{InterpCx, MemoryKind, OpTy};
8+
9+
/// Determines if this type permits "raw" initialization by just transmuting some memory into an
10+
/// instance of `T`.
11+
///
12+
/// `init_kind` indicates if the memory is zero-initialized or left uninitialized. We assume
13+
/// uninitialized memory is mitigated by filling it with 0x01, which reduces the chance of causing
14+
/// LLVM UB.
15+
///
16+
/// By default we check whether that operation would cause *LLVM UB*, i.e., whether the LLVM IR we
17+
/// generate has UB or not. This is a mitigation strategy, which is why we are okay with accepting
18+
/// Rust UB as long as there is no risk of miscompilations. The `strict_init_checks` can be set to
19+
/// do a full check against Rust UB instead (in which case we will also ignore the 0x01-filling and
20+
/// to the full uninit check).
21+
pub fn might_permit_raw_init<'tcx>(
22+
tcx: TyCtxt<'tcx>,
23+
ty: TyAndLayout<'tcx>,
24+
kind: InitKind,
25+
) -> bool {
26+
if tcx.sess.opts.unstable_opts.strict_init_checks {
27+
might_permit_raw_init_strict(ty, tcx, kind)
28+
} else {
29+
let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
30+
might_permit_raw_init_lax(ty, &layout_cx, kind)
31+
}
32+
}
33+
34+
/// Implements the 'strict' version of the `might_permit_raw_init` checks; see that function for
35+
/// details.
36+
fn might_permit_raw_init_strict<'tcx>(
37+
ty: TyAndLayout<'tcx>,
38+
tcx: TyCtxt<'tcx>,
39+
kind: InitKind,
40+
) -> bool {
41+
let machine = CompileTimeInterpreter::new(
42+
Limit::new(0),
43+
/*can_access_statics:*/ false,
44+
/*check_alignment:*/ true,
45+
);
46+
47+
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
48+
49+
let allocated = cx
50+
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
51+
.expect("OOM: failed to allocate for uninit check");
52+
53+
if kind == InitKind::Zero {
54+
cx.write_bytes_ptr(
55+
allocated.ptr,
56+
std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
57+
)
58+
.expect("failed to write bytes for zero valid check");
59+
}
60+
61+
let ot: OpTy<'_, _> = allocated.into();
62+
63+
// Assume that if it failed, it's a validation failure.
64+
// This does *not* actually check that references are dereferenceable, but since all types that
65+
// require dereferenceability also require non-null, we don't actually get any false negatives
66+
// due to this.
67+
cx.validate_operand(&ot).is_ok()
68+
}
69+
70+
/// Implements the 'lax' (default) version of the `might_permit_raw_init` checks; see that function for
71+
/// details.
72+
fn might_permit_raw_init_lax<'tcx>(
73+
this: TyAndLayout<'tcx>,
74+
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
75+
init_kind: InitKind,
76+
) -> bool {
77+
let scalar_allows_raw_init = move |s: Scalar| -> bool {
78+
match init_kind {
79+
InitKind::Zero => {
80+
// The range must contain 0.
81+
s.valid_range(cx).contains(0)
82+
}
83+
InitKind::UninitMitigated0x01Fill => {
84+
// The range must include an 0x01-filled buffer.
85+
let mut val: u128 = 0x01;
86+
for _ in 1..s.size(cx).bytes() {
87+
// For sizes >1, repeat the 0x01.
88+
val = (val << 8) | 0x01;
89+
}
90+
s.valid_range(cx).contains(val)
91+
}
92+
}
93+
};
94+
95+
// Check the ABI.
96+
let valid = match this.abi {
97+
Abi::Uninhabited => false, // definitely UB
98+
Abi::Scalar(s) => scalar_allows_raw_init(s),
99+
Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
100+
Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
101+
Abi::Aggregate { .. } => true, // Fields are checked below.
102+
};
103+
if !valid {
104+
// This is definitely not okay.
105+
return false;
106+
}
107+
108+
// Special magic check for references and boxes (i.e., special pointer types).
109+
if let Some(pointee) = this.ty.builtin_deref(false) {
110+
let pointee = cx.layout_of(pointee.ty).expect("need to be able to compute layouts");
111+
// We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied.
112+
if pointee.align.abi.bytes() > 1 {
113+
// 0x01-filling is not aligned.
114+
return false;
115+
}
116+
if pointee.size.bytes() > 0 {
117+
// A 'fake' integer pointer is not sufficiently dereferenceable.
118+
return false;
119+
}
120+
}
121+
122+
// If we have not found an error yet, we need to recursively descend into fields.
123+
match &this.fields {
124+
FieldsShape::Primitive | FieldsShape::Union { .. } => {}
125+
FieldsShape::Array { .. } => {
126+
// Arrays never have scalar layout in LLVM, so if the array is not actually
127+
// accessed, there is no LLVM UB -- therefore we can skip this.
128+
}
129+
FieldsShape::Arbitrary { offsets, .. } => {
130+
for idx in 0..offsets.len() {
131+
if !might_permit_raw_init_lax(this.field(cx, idx), cx, init_kind) {
132+
// We found a field that is unhappy with this kind of initialization.
133+
return false;
134+
}
135+
}
136+
}
137+
}
138+
139+
match &this.variants {
140+
Variants::Single { .. } => {
141+
// All fields of this single variant have already been checked above, there is nothing
142+
// else to do.
143+
}
144+
Variants::Multiple { .. } => {
145+
// We cannot tell LLVM anything about the details of this multi-variant layout, so
146+
// invalid values "hidden" inside the variant cannot cause LLVM trouble.
147+
}
148+
}
149+
150+
true
151+
}

compiler/rustc_const_eval/src/util/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ mod alignment;
33
mod call_kind;
44
pub mod collect_writes;
55
mod find_self_call;
6+
mod might_permit_raw_init;
67

78
pub use self::aggregate::expand_aggregate;
89
pub use self::alignment::is_disaligned;
910
pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
1011
pub use self::find_self_call::find_self_call;
12+
pub use self::might_permit_raw_init::might_permit_raw_init;

compiler/rustc_hir_analysis/src/check/demand.rs

+27-19
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3232
error: Option<TypeError<'tcx>>,
3333
) {
3434
self.annotate_expected_due_to_let_ty(err, expr, error);
35-
self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
36-
self.suggest_compatible_variants(err, expr, expected, expr_ty);
37-
self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty);
38-
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
39-
return;
40-
}
41-
self.suggest_no_capture_closure(err, expected, expr_ty);
42-
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
43-
self.suggest_missing_parentheses(err, expr);
44-
self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
45-
self.suggest_copied_or_cloned(err, expr, expr_ty, expected);
35+
36+
// Use `||` to give these suggestions a precedence
37+
let _ = self.suggest_missing_parentheses(err, expr)
38+
|| self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr)
39+
|| self.suggest_compatible_variants(err, expr, expected, expr_ty)
40+
|| self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty)
41+
|| self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty)
42+
|| self.suggest_no_capture_closure(err, expected, expr_ty)
43+
|| self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
44+
|| self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
45+
|| self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
46+
|| self.suggest_into(err, expr, expr_ty, expected);
47+
4648
self.note_type_is_not_clone(err, expected, expr_ty, expr);
4749
self.note_need_for_fn_pointer(err, expected, expr_ty);
4850
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
@@ -286,7 +288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
286288
expr: &hir::Expr<'_>,
287289
expected: Ty<'tcx>,
288290
expr_ty: Ty<'tcx>,
289-
) {
291+
) -> bool {
290292
if let ty::Adt(expected_adt, substs) = expected.kind() {
291293
if let hir::ExprKind::Field(base, ident) = expr.kind {
292294
let base_ty = self.typeck_results.borrow().expr_ty(base);
@@ -299,7 +301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
299301
"",
300302
Applicability::MaybeIncorrect,
301303
);
302-
return
304+
return true;
303305
}
304306
}
305307

@@ -338,7 +340,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
338340
} else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) {
339341
vec!["None", "Some(())"]
340342
} else {
341-
return;
343+
return false;
342344
};
343345
if let Some(indent) =
344346
self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
@@ -358,7 +360,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
358360
Applicability::MaybeIncorrect,
359361
);
360362
}
361-
return;
363+
return true;
362364
}
363365
}
364366
}
@@ -445,6 +447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
445447
suggestions_for(&**variant, *ctor_kind, *field_name),
446448
Applicability::MaybeIncorrect,
447449
);
450+
return true;
448451
}
449452
_ => {
450453
// More than one matching variant.
@@ -460,9 +463,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
460463
),
461464
Applicability::MaybeIncorrect,
462465
);
466+
return true;
463467
}
464468
}
465469
}
470+
471+
false
466472
}
467473

468474
fn suggest_non_zero_new_unwrap(
@@ -471,19 +477,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
471477
expr: &hir::Expr<'_>,
472478
expected: Ty<'tcx>,
473479
expr_ty: Ty<'tcx>,
474-
) {
480+
) -> bool {
475481
let tcx = self.tcx;
476482
let (adt, unwrap) = match expected.kind() {
477483
// In case Option<NonZero*> is wanted, but * is provided, suggest calling new
478484
ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
479485
// Unwrap option
480-
let ty::Adt(adt, _) = substs.type_at(0).kind() else { return };
486+
let ty::Adt(adt, _) = substs.type_at(0).kind() else { return false; };
481487

482488
(adt, "")
483489
}
484490
// In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types
485491
ty::Adt(adt, _) => (adt, ".unwrap()"),
486-
_ => return,
492+
_ => return false,
487493
};
488494

489495
let map = [
@@ -502,7 +508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
502508
let Some((s, _)) = map
503509
.iter()
504510
.find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t))
505-
else { return };
511+
else { return false; };
506512

507513
let path = self.tcx.def_path_str(adt.non_enum_variant().def_id);
508514

@@ -514,6 +520,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
514520
],
515521
Applicability::MaybeIncorrect,
516522
);
523+
524+
true
517525
}
518526

519527
pub fn get_conversion_methods(

0 commit comments

Comments
 (0)