Skip to content

Commit

Permalink
Auto merge of rust-lang#113000 - Mark-Simulacrum:beta-backport, r=Mar…
Browse files Browse the repository at this point in the history
…k-Simulacrum

[beta] backport

This PR backports:

- rust-lang#112684: Disable alignment checks on i686-pc-windows-msvc
- rust-lang#112581: [rustdoc] Fix URL encoding of % sign
- rust-lang#112312: Update to LLVM 16.0.5
- rust-lang#112266: Fix type-inference regression in rust-lang#112225
- rust-lang#112062: Make struct layout not depend on unsizeable tail

r? `@Mark-Simulacrum`
  • Loading branch information
bors committed Jun 24, 2023
2 parents 78a6ac0 + f8052fc commit dbf31f1
Show file tree
Hide file tree
Showing 13 changed files with 202 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
98 changes: 54 additions & 44 deletions compiler/rustc_abi/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Type> and Foo<dyn Trait> 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);
}
}
}
}
Expand Down Expand Up @@ -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
Expand All @@ -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<Type>` -> `&Foo<dyn Trait>`, 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))
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 <https://github.com/rust-lang/rust/issues/112225>.
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;
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_mir_transform/src/check_alignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
2 changes: 0 additions & 2 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion src/llvm-project
Submodule llvm-project updated 69 files
+1 −1 .github/workflows/release-tasks.yml
+7 −1 bolt/CMakeLists.txt
+3 −3 bolt/runtime/CMakeLists.txt
+0 −7 clang-tools-extra/clangd/test/CMakeLists.txt
+2 −2 clang-tools-extra/test/clang-tidy/checkers/performance/trivially-destructible.cpp
+1 −1 clang/cmake/caches/Fuchsia-stage2.cmake
+9 −0 clang/docs/ReleaseNotes.rst
+8 −0 clang/include/clang/AST/ExprConcepts.h
+2 −1 clang/include/clang/Basic/DiagnosticSemaKinds.td
+16 −2 clang/include/clang/Sema/Initialization.h
+3 −0 clang/include/clang/Sema/Sema.h
+2 −1 clang/lib/AST/ASTContext.cpp
+15 −4 clang/lib/AST/ExprConcepts.cpp
+1 −0 clang/lib/Driver/ToolChains/Clang.cpp
+5 −1 clang/lib/Format/IntegerLiteralSeparatorFixer.cpp
+2 −1 clang/lib/Sema/SemaAccess.cpp
+1 −1 clang/lib/Sema/SemaDecl.cpp
+18 −8 clang/lib/Sema/SemaExpr.cpp
+201 −134 clang/lib/Sema/SemaInit.cpp
+69 −0 clang/test/CodeGen/paren-list-agg-init.cpp
+4 −1 clang/test/Driver/cl-options.c
+2 −0 clang/test/PCH/cxx2a-constraints.cpp
+38 −0 clang/test/SemaCXX/cxx2a-consteval.cpp
+58 −9 clang/test/SemaCXX/paren-list-agg-init.cpp
+11 −0 clang/test/SemaOpenMP/arm-sve-acle-types.cpp
+18 −0 clang/unittests/Format/IntegerLiteralSeparatorTest.cpp
+2 −2 compiler-rt/cmake/Modules/AddCompilerRT.cmake
+1 −1 libcxx/include/__config
+33 −0 lld/docs/WebAssembly.rst
+2 −0 lld/test/wasm/Inputs/libstub-missing-dep.so
+3 −0 lld/test/wasm/Inputs/libstub-missing-sym.so
+5 −0 lld/test/wasm/Inputs/libstub.so
+48 −0 lld/test/wasm/stub_library.s
+87 −0 lld/test/wasm/why-extract.s
+11 −1 lld/wasm/Config.h
+92 −7 lld/wasm/Driver.cpp
+43 −0 lld/wasm/InputFiles.cpp
+13 −0 lld/wasm/InputFiles.h
+2 −0 lld/wasm/Options.td
+2 −2 lld/wasm/Relocations.cpp
+13 −0 lld/wasm/SymbolTable.cpp
+1 −0 lld/wasm/SymbolTable.h
+4 −0 lld/wasm/Symbols.cpp
+6 −1 lld/wasm/Symbols.h
+2 −2 lld/wasm/Writer.cpp
+1 −1 llvm/CMakeLists.txt
+11 −3 llvm/cmake/modules/AddLLVM.cmake
+0 −10 llvm/cmake/modules/HandleLLVMOptions.cmake
+5 −0 llvm/cmake/modules/LLVM-Config.cmake
+9 −0 llvm/include/llvm/Analysis/AliasAnalysis.h
+6 −6 llvm/include/llvm/Analysis/TargetLibraryInfo.h
+19 −9 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+5 −2 llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
+22 −2 llvm/lib/Target/Hexagon/HexagonPatterns.td
+21 −6 llvm/lib/Target/X86/X86ISelLowering.cpp
+21 −0 llvm/lib/Target/X86/X86InstrAVX512.td
+333 −98 llvm/test/CodeGen/Hexagon/bitmanip.ll
+3 −2 llvm/test/CodeGen/X86/avx512-insert-extract.ll
+46 −0 llvm/test/CodeGen/X86/avx512bf16-vl-intrinsics.ll
+5 −0 llvm/test/CodeGen/X86/prefetchi.ll
+16 −0 llvm/test/CodeGen/X86/setcc.ll
+6 −1 llvm/test/Instrumentation/AddressSanitizer/experiment.ll
+3 −1 llvm/test/Instrumentation/AddressSanitizer/mem-intrinsics.ll
+11 −1 llvm/test/Instrumentation/ThreadSanitizer/atomic.ll
+41 −0 llvm/test/Transforms/GVN/pr63019.ll
+8 −0 llvm/test/tools/llvm-mca/X86/Generic/no-duplicate-symbols.s
+11 −8 llvm/tools/llvm-mca/llvm-mca.cpp
+1 −1 llvm/utils/gn/secondary/llvm/version.gni
+1 −1 llvm/utils/lit/lit/__init__.py
18 changes: 18 additions & 0 deletions tests/ui/async-await/issues/issue-112225-1.rs
Original file line number Diff line number Diff line change
@@ -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<R, Fut, F>(_tokio_fut: Fut, _glib_closure: F)
where
Fut: Future<Output = R>,
F: FnOnce(R),
{
}
20 changes: 20 additions & 0 deletions tests/ui/async-await/issues/issue-112225-2.rs
Original file line number Diff line number Diff line change
@@ -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, T>(_fut: Fut, _val: T, ) {}
17 changes: 17 additions & 0 deletions tests/ui/async-await/issues/issue-112225-2.stderr
Original file line number Diff line number Diff line change
@@ -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`.
25 changes: 25 additions & 0 deletions tests/ui/layout/issue-112048-unsizing-field-order.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// run-pass

// Check that unsizing doesn't reorder fields.

#![allow(dead_code)]

use std::fmt::Debug;

#[derive(Debug)]
struct GcNode<T: ?Sized> {
gets_swapped_with_next: usize,
next: Option<&'static GcNode<dyn Debug>>,
tail: T,
}

fn main() {
let node: Box<GcNode<dyn Debug>> = 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());
}
30 changes: 30 additions & 0 deletions tests/ui/layout/issue-112048-unsizing-niche.rs
Original file line number Diff line number Diff line change
@@ -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<T: ?Sized> {
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<Tail>, niche),
core::mem::offset_of!(WideptrField<dyn Send>, niche)
);
}
1 change: 1 addition & 0 deletions tests/ui/mir/mir_alignment_check.rs
Original file line number Diff line number Diff line change
@@ -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

Expand Down
21 changes: 21 additions & 0 deletions tests/ui/mir/mir_alignment_check_i686-pc-windows-msvc.rs
Original file line number Diff line number Diff line change
@@ -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::<u8>();
unsafe {
let misaligned = ptr.add(4).cast::<u64>();
assert!(misaligned.addr() % 8 != 0);
assert!(misaligned.addr() % 4 == 0);
*misaligned = 42;
}
}

0 comments on commit dbf31f1

Please sign in to comment.