diff --git a/.gitmodules b/.gitmodules index 4596ae17d0238..6b7160bfe1530 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,7 +25,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/16.0-2023-04-05 + branch = rustc/16.0-2023-06-05 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index f11c1c77f9cfc..73f9deb3143a7 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -57,48 +57,54 @@ pub trait LayoutCalculator { // run and bias niches to the right and then check which one is closer to one of the struct's // edges. if let Some(layout) = &layout { - if let Some(niche) = layout.largest_niche { - let head_space = niche.offset.bytes(); - let niche_length = niche.value.size(dl).bytes(); - let tail_space = layout.size.bytes() - head_space - niche_length; - - // This may end up doing redundant work if the niche is already in the last field - // (e.g. a trailing bool) and there is tail padding. But it's non-trivial to get - // the unpadded size so we try anyway. - if fields.len() > 1 && head_space != 0 && tail_space > 0 { - let alt_layout = univariant(self, dl, fields, repr, kind, NicheBias::End) - .expect("alt layout should always work"); - let niche = alt_layout - .largest_niche - .expect("alt layout should have a niche like the regular one"); - let alt_head_space = niche.offset.bytes(); - let alt_niche_len = niche.value.size(dl).bytes(); - let alt_tail_space = alt_layout.size.bytes() - alt_head_space - alt_niche_len; - - debug_assert_eq!(layout.size.bytes(), alt_layout.size.bytes()); - - let prefer_alt_layout = - alt_head_space > head_space && alt_head_space > tail_space; - - debug!( - "sz: {}, default_niche_at: {}+{}, default_tail_space: {}, alt_niche_at/head_space: {}+{}, alt_tail: {}, num_fields: {}, better: {}\n\ - layout: {}\n\ - alt_layout: {}\n", - layout.size.bytes(), - head_space, - niche_length, - tail_space, - alt_head_space, - alt_niche_len, - alt_tail_space, - layout.fields.count(), - prefer_alt_layout, - format_field_niches(&layout, &fields, &dl), - format_field_niches(&alt_layout, &fields, &dl), - ); - - if prefer_alt_layout { - return Some(alt_layout); + // Don't try to calculate an end-biased layout for unsizable structs, + // otherwise we could end up with different layouts for + // Foo and Foo which would break unsizing + if !matches!(kind, StructKind::MaybeUnsized) { + if let Some(niche) = layout.largest_niche { + let head_space = niche.offset.bytes(); + let niche_length = niche.value.size(dl).bytes(); + let tail_space = layout.size.bytes() - head_space - niche_length; + + // This may end up doing redundant work if the niche is already in the last field + // (e.g. a trailing bool) and there is tail padding. But it's non-trivial to get + // the unpadded size so we try anyway. + if fields.len() > 1 && head_space != 0 && tail_space > 0 { + let alt_layout = univariant(self, dl, fields, repr, kind, NicheBias::End) + .expect("alt layout should always work"); + let niche = alt_layout + .largest_niche + .expect("alt layout should have a niche like the regular one"); + let alt_head_space = niche.offset.bytes(); + let alt_niche_len = niche.value.size(dl).bytes(); + let alt_tail_space = + alt_layout.size.bytes() - alt_head_space - alt_niche_len; + + debug_assert_eq!(layout.size.bytes(), alt_layout.size.bytes()); + + let prefer_alt_layout = + alt_head_space > head_space && alt_head_space > tail_space; + + debug!( + "sz: {}, default_niche_at: {}+{}, default_tail_space: {}, alt_niche_at/head_space: {}+{}, alt_tail: {}, num_fields: {}, better: {}\n\ + layout: {}\n\ + alt_layout: {}\n", + layout.size.bytes(), + head_space, + niche_length, + tail_space, + alt_head_space, + alt_niche_len, + alt_tail_space, + layout.fields.count(), + prefer_alt_layout, + format_field_niches(&layout, &fields, &dl), + format_field_niches(&alt_layout, &fields, &dl), + ); + + if prefer_alt_layout { + return Some(alt_layout); + } } } } @@ -828,6 +834,7 @@ fn univariant( if optimize && fields.len() > 1 { let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; let optimizing = &mut inverse_memory_index.raw[..end]; + let fields_excluding_tail = &fields.raw[..end]; // If `-Z randomize-layout` was enabled for the type definition we can shuffle // the field ordering to try and catch some code making assumptions about layouts @@ -844,8 +851,11 @@ fn univariant( } // Otherwise we just leave things alone and actually optimize the type's fields } else { - let max_field_align = fields.iter().map(|f| f.align().abi.bytes()).max().unwrap_or(1); - let largest_niche_size = fields + // To allow unsizing `&Foo` -> `&Foo`, the layout of the struct must + // not depend on the layout of the tail. + let max_field_align = + fields_excluding_tail.iter().map(|f| f.align().abi.bytes()).max().unwrap_or(1); + let largest_niche_size = fields_excluding_tail .iter() .filter_map(|f| f.largest_niche()) .map(|n| n.available(dl)) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 72c42f8e78952..eba5c829e396d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -362,7 +362,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } - let is_closure = matches!(arg.kind, ExprKind::Closure { .. }); + // For this check, we do *not* want to treat async generator closures (async blocks) + // as proper closures. Doing so would regress type inference when feeding + // the return value of an argument-position async block to an argument-position + // closure wrapped in a block. + // See . + let is_closure = if let ExprKind::Closure(closure) = arg.kind { + !tcx.generator_is_async(closure.def_id.to_def_id()) + } else { + false + }; if is_closure != check_closures { continue; } diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index 1fe8ea0789286..ea07806887ae8 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -14,6 +14,10 @@ pub struct CheckAlignment; impl<'tcx> MirPass<'tcx> for CheckAlignment { fn is_enabled(&self, sess: &Session) -> bool { + // FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows + if sess.target.llvm_target == "i686-pc-windows-msvc" { + return false; + } sess.opts.debug_assertions } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 42e27d35a94b1..9e3b5d10a1fd8 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1933,8 +1933,6 @@ pub(crate) fn small_url_encode(s: String) -> String { // While the same is not true for hashes, rustdoc only needs to be // consistent with itself when encoding them. st += "+"; - } else if b == b'%' { - st += "%%"; } else { write!(st, "%{:02X}", b).unwrap(); } diff --git a/src/llvm-project b/src/llvm-project index 533d3f338b804..22897bce7bfed 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 533d3f338b804d54e5d0ac4fba6276af23002d9c +Subproject commit 22897bce7bfedc9cd3953a33419b346936263500 diff --git a/tests/ui/async-await/issues/issue-112225-1.rs b/tests/ui/async-await/issues/issue-112225-1.rs new file mode 100644 index 0000000000000..e28cbee214e1a --- /dev/null +++ b/tests/ui/async-await/issues/issue-112225-1.rs @@ -0,0 +1,18 @@ +// check-pass +// edition:2021 + +use core::future::Future; + +fn main() { + do_async(async { (0,) }, { + // closure must be inside block + |info| println!("{:?}", info.0) + }); +} + +fn do_async(_tokio_fut: Fut, _glib_closure: F) +where + Fut: Future, + F: FnOnce(R), +{ +} diff --git a/tests/ui/async-await/issues/issue-112225-2.rs b/tests/ui/async-await/issues/issue-112225-2.rs new file mode 100644 index 0000000000000..50fa1a79b6beb --- /dev/null +++ b/tests/ui/async-await/issues/issue-112225-2.rs @@ -0,0 +1,20 @@ +// edition:2021 + +// With the current compiler logic, we cannot have both the `112225-1` case, +// and this `112225-2` case working, as the type inference depends on the evaluation +// order, and there is some explicit ordering going on. +// See the `check_closures` part in `FnCtxt::check_argument_types`. +// The `112225-1` case was a regression in real world code, whereas the `112225-2` +// case never used to work prior to 1.70. + +use core::future::Future; + +fn main() { + let x = Default::default(); + //~^ ERROR: type annotations needed + do_async( + async { x.0; }, + { || { let _: &(i32,) = &x; } }, + ); +} +fn do_async(_fut: Fut, _val: T, ) {} diff --git a/tests/ui/async-await/issues/issue-112225-2.stderr b/tests/ui/async-await/issues/issue-112225-2.stderr new file mode 100644 index 0000000000000..5926a4f3995ad --- /dev/null +++ b/tests/ui/async-await/issues/issue-112225-2.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed + --> $DIR/issue-112225-2.rs:13:9 + | +LL | let x = Default::default(); + | ^ +... +LL | async { x.0; }, + | - type must be known at this point + | +help: consider giving `x` an explicit type + | +LL | let x: /* Type */ = Default::default(); + | ++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/layout/issue-112048-unsizing-field-order.rs b/tests/ui/layout/issue-112048-unsizing-field-order.rs new file mode 100644 index 0000000000000..ebc4b9e98b7ab --- /dev/null +++ b/tests/ui/layout/issue-112048-unsizing-field-order.rs @@ -0,0 +1,25 @@ +// run-pass + +// Check that unsizing doesn't reorder fields. + +#![allow(dead_code)] + +use std::fmt::Debug; + +#[derive(Debug)] +struct GcNode { + gets_swapped_with_next: usize, + next: Option<&'static GcNode>, + tail: T, +} + +fn main() { + let node: Box> = Box::new(GcNode { + gets_swapped_with_next: 42, + next: None, + tail: Box::new(1), + }); + + assert_eq!(node.gets_swapped_with_next, 42); + assert!(node.next.is_none()); +} diff --git a/tests/ui/layout/issue-112048-unsizing-niche.rs b/tests/ui/layout/issue-112048-unsizing-niche.rs new file mode 100644 index 0000000000000..23588ba36ee59 --- /dev/null +++ b/tests/ui/layout/issue-112048-unsizing-niche.rs @@ -0,0 +1,30 @@ +// run-pass + +// Check that unsizing does not change which field is considered for niche layout. + +#![feature(offset_of)] +#![allow(dead_code)] + +#[derive(Clone)] +struct WideptrField { + first: usize, + second: usize, + niche: NicheAtEnd, + tail: T, +} + +#[derive(Clone)] +#[repr(C)] +struct NicheAtEnd { + arr: [u8; 7], + b: bool, +} + +type Tail = [bool; 8]; + +fn main() { + assert_eq!( + core::mem::offset_of!(WideptrField, niche), + core::mem::offset_of!(WideptrField, niche) + ); +} diff --git a/tests/ui/mir/mir_alignment_check.rs b/tests/ui/mir/mir_alignment_check.rs index 68a5384b30d78..d1bf3d46a7c7a 100644 --- a/tests/ui/mir/mir_alignment_check.rs +++ b/tests/ui/mir/mir_alignment_check.rs @@ -1,5 +1,6 @@ // run-fail // ignore-wasm32-bare: No panic messages +// ignore-i686-pc-windows-msvc: #112480 // compile-flags: -C debug-assertions // error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is diff --git a/tests/ui/mir/mir_alignment_check_i686-pc-windows-msvc.rs b/tests/ui/mir/mir_alignment_check_i686-pc-windows-msvc.rs new file mode 100644 index 0000000000000..56388c1047e9a --- /dev/null +++ b/tests/ui/mir/mir_alignment_check_i686-pc-windows-msvc.rs @@ -0,0 +1,21 @@ +// run-pass +// only-i686-pc-windows-msvc +// compile-flags: -Copt-level=0 -Cdebug-assertions=yes + +// MSVC isn't sure if on 32-bit Windows its u64 type is 8-byte-aligned or 4-byte-aligned. +// So this test ensures that on i686-pc-windows-msvc, we do not insert a runtime check +// that will fail on dereferencing of a pointer to u64 which is not 8-byte-aligned but is +// 4-byte-aligned. + +#![feature(strict_provenance)] + +fn main() { + let mut x = [0u64; 2]; + let ptr: *mut u8 = x.as_mut_ptr().cast::(); + unsafe { + let misaligned = ptr.add(4).cast::(); + assert!(misaligned.addr() % 8 != 0); + assert!(misaligned.addr() % 4 == 0); + *misaligned = 42; + } +}