Skip to content

[beta] backport #113000

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
}