Skip to content

Commit b4e54c6

Browse files
committedSep 11, 2023
Auto merge of #115767 - matthiaskrgr:rollup-byf3lvq, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #115548 (Extract parallel operations in `rustc_data_structures::sync` into a new `parallel` submodule) - #115591 (Add regression test for LLVM 17-rc3 miscompile) - #115631 (Don't ICE when computing ctype's `repr_nullable_ptr` for possibly-unsized ty) - #115708 (fix homogeneous_aggregate not ignoring some ZST) - #115730 (Some more small driver refactors) - #115749 (Allow loading the SMIR for constants and statics) - #115757 (Add a test for #108030) - #115761 (Update books) r? `@ghost` `@rustbot` modify labels: rollup
·
1.88.01.74.0
2 parents e2b3676 + 059231f commit b4e54c6

File tree

25 files changed

+447
-201
lines changed

25 files changed

+447
-201
lines changed
 

‎compiler/rustc_data_structures/src/sync.rs

Lines changed: 5 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,21 @@
4141
//! [^2] `MTLockRef` is a typedef.
4242
4343
pub use crate::marker::*;
44-
use parking_lot::Mutex;
45-
use std::any::Any;
4644
use std::collections::HashMap;
4745
use std::hash::{BuildHasher, Hash};
4846
use std::ops::{Deref, DerefMut};
49-
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
5047

5148
mod lock;
5249
pub use lock::{Lock, LockGuard, Mode};
5350

5451
mod worker_local;
5552
pub use worker_local::{Registry, WorkerLocal};
5653

54+
mod parallel;
55+
#[cfg(parallel_compiler)]
56+
pub use parallel::scope;
57+
pub use parallel::{join, par_for_each_in, par_map, parallel_guard};
58+
5759
pub use std::sync::atomic::Ordering;
5860
pub use std::sync::atomic::Ordering::SeqCst;
5961

@@ -107,37 +109,6 @@ mod mode {
107109

108110
pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
109111

110-
/// A guard used to hold panics that occur during a parallel section to later by unwound.
111-
/// This is used for the parallel compiler to prevent fatal errors from non-deterministically
112-
/// hiding errors by ensuring that everything in the section has completed executing before
113-
/// continuing with unwinding. It's also used for the non-parallel code to ensure error message
114-
/// output match the parallel compiler for testing purposes.
115-
pub struct ParallelGuard {
116-
panic: Mutex<Option<Box<dyn Any + std::marker::Send + 'static>>>,
117-
}
118-
119-
impl ParallelGuard {
120-
pub fn run<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
121-
catch_unwind(AssertUnwindSafe(f))
122-
.map_err(|err| {
123-
*self.panic.lock() = Some(err);
124-
})
125-
.ok()
126-
}
127-
}
128-
129-
/// This gives access to a fresh parallel guard in the closure and will unwind any panics
130-
/// caught in it after the closure returns.
131-
#[inline]
132-
pub fn parallel_guard<R>(f: impl FnOnce(&ParallelGuard) -> R) -> R {
133-
let guard = ParallelGuard { panic: Mutex::new(None) };
134-
let ret = f(&guard);
135-
if let Some(panic) = guard.panic.into_inner() {
136-
resume_unwind(panic);
137-
}
138-
ret
139-
}
140-
141112
cfg_if! {
142113
if #[cfg(not(parallel_compiler))] {
143114
use std::ops::Add;
@@ -229,44 +200,6 @@ cfg_if! {
229200
pub type AtomicU32 = Atomic<u32>;
230201
pub type AtomicU64 = Atomic<u64>;
231202

232-
pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
233-
where A: FnOnce() -> RA,
234-
B: FnOnce() -> RB
235-
{
236-
let (a, b) = parallel_guard(|guard| {
237-
let a = guard.run(oper_a);
238-
let b = guard.run(oper_b);
239-
(a, b)
240-
});
241-
(a.unwrap(), b.unwrap())
242-
}
243-
244-
#[macro_export]
245-
macro_rules! parallel {
246-
($($blocks:block),*) => {{
247-
$crate::sync::parallel_guard(|guard| {
248-
$(guard.run(|| $blocks);)*
249-
});
250-
}}
251-
}
252-
253-
pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item) + Sync + Send) {
254-
parallel_guard(|guard| {
255-
t.into_iter().for_each(|i| {
256-
guard.run(|| for_each(i));
257-
});
258-
})
259-
}
260-
261-
pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>(
262-
t: T,
263-
mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R,
264-
) -> C {
265-
parallel_guard(|guard| {
266-
t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()
267-
})
268-
}
269-
270203
pub use std::rc::Rc as Lrc;
271204
pub use std::rc::Weak as Weak;
272205
pub use std::cell::Ref as ReadGuard;
@@ -372,105 +305,6 @@ cfg_if! {
372305

373306
use std::thread;
374307

375-
#[inline]
376-
pub fn join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB)
377-
where
378-
A: FnOnce() -> RA + DynSend,
379-
B: FnOnce() -> RB + DynSend,
380-
{
381-
if mode::is_dyn_thread_safe() {
382-
let oper_a = FromDyn::from(oper_a);
383-
let oper_b = FromDyn::from(oper_b);
384-
let (a, b) = rayon::join(move || FromDyn::from(oper_a.into_inner()()), move || FromDyn::from(oper_b.into_inner()()));
385-
(a.into_inner(), b.into_inner())
386-
} else {
387-
let (a, b) = parallel_guard(|guard| {
388-
let a = guard.run(oper_a);
389-
let b = guard.run(oper_b);
390-
(a, b)
391-
});
392-
(a.unwrap(), b.unwrap())
393-
}
394-
}
395-
396-
// This function only works when `mode::is_dyn_thread_safe()`.
397-
pub fn scope<'scope, OP, R>(op: OP) -> R
398-
where
399-
OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend,
400-
R: DynSend,
401-
{
402-
let op = FromDyn::from(op);
403-
rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner()
404-
}
405-
406-
/// Runs a list of blocks in parallel. The first block is executed immediately on
407-
/// the current thread. Use that for the longest running block.
408-
#[macro_export]
409-
macro_rules! parallel {
410-
(impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => {
411-
parallel!(impl $fblock [$block, $($c,)*] [$($rest),*])
412-
};
413-
(impl $fblock:block [$($blocks:expr,)*] []) => {
414-
::rustc_data_structures::sync::scope(|s| {
415-
$(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks);
416-
s.spawn(move |_| block.into_inner()());)*
417-
(|| $fblock)();
418-
});
419-
};
420-
($fblock:block, $($blocks:block),*) => {
421-
if rustc_data_structures::sync::is_dyn_thread_safe() {
422-
// Reverse the order of the later blocks since Rayon executes them in reverse order
423-
// when using a single thread. This ensures the execution order matches that
424-
// of a single threaded rustc.
425-
parallel!(impl $fblock [] [$($blocks),*]);
426-
} else {
427-
$crate::sync::parallel_guard(|guard| {
428-
guard.run(|| $fblock);
429-
$(guard.run(|| $blocks);)*
430-
});
431-
}
432-
};
433-
}
434-
435-
use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
436-
437-
pub fn par_for_each_in<I, T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>>(
438-
t: T,
439-
for_each: impl Fn(I) + DynSync + DynSend
440-
) {
441-
parallel_guard(|guard| {
442-
if mode::is_dyn_thread_safe() {
443-
let for_each = FromDyn::from(for_each);
444-
t.into_par_iter().for_each(|i| {
445-
guard.run(|| for_each(i));
446-
});
447-
} else {
448-
t.into_iter().for_each(|i| {
449-
guard.run(|| for_each(i));
450-
});
451-
}
452-
});
453-
}
454-
455-
pub fn par_map<
456-
I,
457-
T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>,
458-
R: std::marker::Send,
459-
C: FromIterator<R> + FromParallelIterator<R>
460-
>(
461-
t: T,
462-
map: impl Fn(I) -> R + DynSync + DynSend
463-
) -> C {
464-
parallel_guard(|guard| {
465-
if mode::is_dyn_thread_safe() {
466-
let map = FromDyn::from(map);
467-
t.into_par_iter().filter_map(|i| guard.run(|| map(i))).collect()
468-
} else {
469-
t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()
470-
}
471-
})
472-
}
473-
474308
/// This makes locks panic if they are already held.
475309
/// It is only useful when you are running in a single thread
476310
const ERROR_CHECKING: bool = false;
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
//! This module defines parallel operations that are implemented in
2+
//! one way for the serial compiler, and another way the parallel compiler.
3+
4+
#![allow(dead_code)]
5+
6+
use parking_lot::Mutex;
7+
use std::any::Any;
8+
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
9+
10+
#[cfg(not(parallel_compiler))]
11+
pub use disabled::*;
12+
#[cfg(parallel_compiler)]
13+
pub use enabled::*;
14+
15+
/// A guard used to hold panics that occur during a parallel section to later by unwound.
16+
/// This is used for the parallel compiler to prevent fatal errors from non-deterministically
17+
/// hiding errors by ensuring that everything in the section has completed executing before
18+
/// continuing with unwinding. It's also used for the non-parallel code to ensure error message
19+
/// output match the parallel compiler for testing purposes.
20+
pub struct ParallelGuard {
21+
panic: Mutex<Option<Box<dyn Any + Send + 'static>>>,
22+
}
23+
24+
impl ParallelGuard {
25+
pub fn run<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
26+
catch_unwind(AssertUnwindSafe(f))
27+
.map_err(|err| {
28+
*self.panic.lock() = Some(err);
29+
})
30+
.ok()
31+
}
32+
}
33+
34+
/// This gives access to a fresh parallel guard in the closure and will unwind any panics
35+
/// caught in it after the closure returns.
36+
#[inline]
37+
pub fn parallel_guard<R>(f: impl FnOnce(&ParallelGuard) -> R) -> R {
38+
let guard = ParallelGuard { panic: Mutex::new(None) };
39+
let ret = f(&guard);
40+
if let Some(panic) = guard.panic.into_inner() {
41+
resume_unwind(panic);
42+
}
43+
ret
44+
}
45+
46+
mod disabled {
47+
use crate::sync::parallel_guard;
48+
49+
#[macro_export]
50+
#[cfg(not(parallel_compiler))]
51+
macro_rules! parallel {
52+
($($blocks:block),*) => {{
53+
$crate::sync::parallel_guard(|guard| {
54+
$(guard.run(|| $blocks);)*
55+
});
56+
}}
57+
}
58+
59+
pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
60+
where
61+
A: FnOnce() -> RA,
62+
B: FnOnce() -> RB,
63+
{
64+
let (a, b) = parallel_guard(|guard| {
65+
let a = guard.run(oper_a);
66+
let b = guard.run(oper_b);
67+
(a, b)
68+
});
69+
(a.unwrap(), b.unwrap())
70+
}
71+
72+
pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item)) {
73+
parallel_guard(|guard| {
74+
t.into_iter().for_each(|i| {
75+
guard.run(|| for_each(i));
76+
});
77+
})
78+
}
79+
80+
pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>(
81+
t: T,
82+
mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R,
83+
) -> C {
84+
parallel_guard(|guard| t.into_iter().filter_map(|i| guard.run(|| map(i))).collect())
85+
}
86+
}
87+
88+
#[cfg(parallel_compiler)]
89+
mod enabled {
90+
use crate::sync::{mode, parallel_guard, DynSend, DynSync, FromDyn};
91+
92+
/// Runs a list of blocks in parallel. The first block is executed immediately on
93+
/// the current thread. Use that for the longest running block.
94+
#[macro_export]
95+
macro_rules! parallel {
96+
(impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => {
97+
parallel!(impl $fblock [$block, $($c,)*] [$($rest),*])
98+
};
99+
(impl $fblock:block [$($blocks:expr,)*] []) => {
100+
::rustc_data_structures::sync::scope(|s| {
101+
$(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks);
102+
s.spawn(move |_| block.into_inner()());)*
103+
(|| $fblock)();
104+
});
105+
};
106+
($fblock:block, $($blocks:block),*) => {
107+
if rustc_data_structures::sync::is_dyn_thread_safe() {
108+
// Reverse the order of the later blocks since Rayon executes them in reverse order
109+
// when using a single thread. This ensures the execution order matches that
110+
// of a single threaded rustc.
111+
parallel!(impl $fblock [] [$($blocks),*]);
112+
} else {
113+
$crate::sync::parallel_guard(|guard| {
114+
guard.run(|| $fblock);
115+
$(guard.run(|| $blocks);)*
116+
});
117+
}
118+
};
119+
}
120+
121+
// This function only works when `mode::is_dyn_thread_safe()`.
122+
pub fn scope<'scope, OP, R>(op: OP) -> R
123+
where
124+
OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend,
125+
R: DynSend,
126+
{
127+
let op = FromDyn::from(op);
128+
rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner()
129+
}
130+
131+
#[inline]
132+
pub fn join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB)
133+
where
134+
A: FnOnce() -> RA + DynSend,
135+
B: FnOnce() -> RB + DynSend,
136+
{
137+
if mode::is_dyn_thread_safe() {
138+
let oper_a = FromDyn::from(oper_a);
139+
let oper_b = FromDyn::from(oper_b);
140+
let (a, b) = rayon::join(
141+
move || FromDyn::from(oper_a.into_inner()()),
142+
move || FromDyn::from(oper_b.into_inner()()),
143+
);
144+
(a.into_inner(), b.into_inner())
145+
} else {
146+
super::disabled::join(oper_a, oper_b)
147+
}
148+
}
149+
150+
use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
151+
152+
pub fn par_for_each_in<I, T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>>(
153+
t: T,
154+
for_each: impl Fn(I) + DynSync + DynSend,
155+
) {
156+
parallel_guard(|guard| {
157+
if mode::is_dyn_thread_safe() {
158+
let for_each = FromDyn::from(for_each);
159+
t.into_par_iter().for_each(|i| {
160+
guard.run(|| for_each(i));
161+
});
162+
} else {
163+
t.into_iter().for_each(|i| {
164+
guard.run(|| for_each(i));
165+
});
166+
}
167+
});
168+
}
169+
170+
pub fn par_map<
171+
I,
172+
T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>,
173+
R: std::marker::Send,
174+
C: FromIterator<R> + FromParallelIterator<R>,
175+
>(
176+
t: T,
177+
map: impl Fn(I) -> R + DynSync + DynSend,
178+
) -> C {
179+
parallel_guard(|guard| {
180+
if mode::is_dyn_thread_safe() {
181+
let map = FromDyn::from(map);
182+
t.into_par_iter().filter_map(|i| guard.run(|| map(i))).collect()
183+
} else {
184+
t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()
185+
}
186+
})
187+
}
188+
}

‎compiler/rustc_driver_impl/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,10 @@ pub fn abort_on_err<T>(result: Result<T, ErrorGuaranteed>, sess: &Session) -> T
162162
pub trait Callbacks {
163163
/// Called before creating the compiler instance
164164
fn config(&mut self, _config: &mut interface::Config) {}
165-
/// Called after parsing. Return value instructs the compiler whether to
165+
/// Called after parsing the crate root. Submodules are not yet parsed when
166+
/// this callback is called. Return value instructs the compiler whether to
166167
/// continue the compilation afterwards (defaults to `Compilation::Continue`)
167-
fn after_parsing<'tcx>(
168+
fn after_crate_root_parsing<'tcx>(
168169
&mut self,
169170
_compiler: &interface::Compiler,
170171
_queries: &'tcx Queries<'tcx>,
@@ -184,7 +185,6 @@ pub trait Callbacks {
184185
/// continue the compilation afterwards (defaults to `Compilation::Continue`)
185186
fn after_analysis<'tcx>(
186187
&mut self,
187-
_handler: &EarlyErrorHandler,
188188
_compiler: &interface::Compiler,
189189
_queries: &'tcx Queries<'tcx>,
190190
) -> Compilation {
@@ -407,7 +407,7 @@ fn run_compiler(
407407
return early_exit();
408408
}
409409

410-
if callbacks.after_parsing(compiler, queries) == Compilation::Stop {
410+
if callbacks.after_crate_root_parsing(compiler, queries) == Compilation::Stop {
411411
return early_exit();
412412
}
413413

@@ -445,7 +445,7 @@ fn run_compiler(
445445

446446
queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?;
447447

448-
if callbacks.after_analysis(&handler, compiler, queries) == Compilation::Stop {
448+
if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
449449
return early_exit();
450450
}
451451

‎compiler/rustc_interface/src/queries.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ impl<'tcx> Queries<'tcx> {
114114
.compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit()))
115115
}
116116

117+
#[deprecated = "pre_configure may be made private in the future. If you need it please open an issue with your use case."]
117118
pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> {
118119
self.pre_configure.compute(|| {
119120
let mut krate = self.parse()?.steal();
@@ -171,6 +172,7 @@ impl<'tcx> Queries<'tcx> {
171172
pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
172173
self.gcx.compute(|| {
173174
let sess = self.session();
175+
#[allow(deprecated)]
174176
let (krate, pre_configured_attrs) = self.pre_configure()?.steal();
175177

176178
// parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.

‎compiler/rustc_lint/src/types.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,12 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
923923
}
924924

925925
// Return the nullable type this Option-like enum can be safely represented with.
926-
let field_ty_abi = &tcx.layout_of(param_env.and(field_ty)).unwrap().abi;
926+
let field_ty_layout = tcx.layout_of(param_env.and(field_ty));
927+
if field_ty_layout.is_err() && !field_ty.has_non_region_param() {
928+
bug!("should be able to compute the layout of non-polymorphic type");
929+
}
930+
931+
let field_ty_abi = &field_ty_layout.ok()?.abi;
927932
if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
928933
match field_ty_scalar.valid_range(&tcx) {
929934
WrappingRange { start: 0, end }

‎compiler/rustc_smir/src/rustc_internal/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use rustc_driver::{Callbacks, Compilation, RunCompiler};
1616
use rustc_interface::{interface, Queries};
1717
use rustc_middle::mir::interpret::AllocId;
1818
use rustc_middle::ty::TyCtxt;
19-
use rustc_session::EarlyErrorHandler;
2019
pub use rustc_span::def_id::{CrateNum, DefId};
2120

2221
fn with_tables<R>(mut f: impl FnMut(&mut Tables<'_>) -> R) -> R {
@@ -233,7 +232,6 @@ where
233232
/// continue the compilation afterwards (defaults to `Compilation::Continue`)
234233
fn after_analysis<'tcx>(
235234
&mut self,
236-
_handler: &EarlyErrorHandler,
237235
_compiler: &interface::Compiler,
238236
queries: &'tcx Queries<'tcx>,
239237
) -> Compilation {

‎compiler/rustc_smir/src/rustc_smir/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ impl<'tcx> Context for Tables<'tcx> {
8484

8585
fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body {
8686
let def_id = self[item];
87-
let mir = self.tcx.optimized_mir(def_id);
87+
let mir = self.tcx.instance_mir(ty::InstanceDef::Item(def_id));
8888
stable_mir::mir::Body {
8989
blocks: mir
9090
.basic_blocks

‎compiler/rustc_target/src/abi/call/mod.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
382382
/// only a single type (e.g., `(u32, u32)`). Such aggregates are often
383383
/// special-cased in ABIs.
384384
///
385-
/// Note: We generally ignore fields of zero-sized type when computing
386-
/// this value (see #56877).
385+
/// Note: We generally ignore 1-ZST fields when computing this value (see #56877).
387386
///
388387
/// This is public so that it can be used in unit tests, but
389388
/// should generally only be relevant to the ABI details of
@@ -441,12 +440,18 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
441440
let mut total = start;
442441

443442
for i in 0..layout.fields.count() {
443+
let field = layout.field(cx, i);
444+
if field.is_1zst() {
445+
// No data here and no impact on layout, can be ignored.
446+
// (We might be able to also ignore all aligned ZST but that's less clear.)
447+
continue;
448+
}
449+
444450
if !is_union && total != layout.fields.offset(i) {
451+
// This field isn't just after the previous one we considered, abort.
445452
return Err(Heterogeneous);
446453
}
447454

448-
let field = layout.field(cx, i);
449-
450455
result = result.merge(field.homogeneous_aggregate(cx)?)?;
451456

452457
// Keep track of the offset (without padding).

‎src/doc/nomicon

‎src/tools/miri/src/bin/miri.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
5959

6060
fn after_analysis<'tcx>(
6161
&mut self,
62-
handler: &EarlyErrorHandler,
6362
_: &rustc_interface::interface::Compiler,
6463
queries: &'tcx rustc_interface::Queries<'tcx>,
6564
) -> Compilation {
@@ -68,7 +67,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
6867
tcx.sess.fatal("miri cannot be run on programs that fail compilation");
6968
}
7069

71-
init_late_loggers(handler, tcx);
70+
let handler = EarlyErrorHandler::new(tcx.sess.opts.error_format);
71+
init_late_loggers(&handler, tcx);
7272
if !tcx.crate_types().contains(&CrateType::Executable) {
7373
tcx.sess.fatal("miri only makes sense on bin crates");
7474
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// compile-flags: -O -Ccodegen-units=1
2+
3+
#![crate_type = "lib"]
4+
5+
#[repr(i64)]
6+
pub enum Boolean {
7+
False = 0,
8+
True = 1,
9+
}
10+
11+
impl Clone for Boolean {
12+
fn clone(&self) -> Self {
13+
*self
14+
}
15+
}
16+
17+
impl Copy for Boolean {}
18+
19+
extern "C" {
20+
fn set_value(foo: *mut i64);
21+
fn bar();
22+
}
23+
24+
pub fn foo(x: bool) {
25+
let mut foo = core::mem::MaybeUninit::<i64>::uninit();
26+
unsafe {
27+
set_value(foo.as_mut_ptr());
28+
}
29+
30+
if x {
31+
let l1 = unsafe { *foo.as_mut_ptr().cast::<Boolean>() };
32+
if matches!(l1, Boolean::False) {
33+
unsafe {
34+
*foo.as_mut_ptr() = 0;
35+
}
36+
}
37+
}
38+
39+
let l2 = unsafe { *foo.as_mut_ptr() };
40+
if l2 == 2 {
41+
// CHECK: call void @bar
42+
unsafe {
43+
bar();
44+
}
45+
}
46+
}

‎tests/run-make-fulldeps/obtain-borrowck/driver.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use rustc_interface::{Config, Queries};
2727
use rustc_middle::query::queries::mir_borrowck::ProvidedValue;
2828
use rustc_middle::query::{ExternProviders, Providers};
2929
use rustc_middle::ty::TyCtxt;
30-
use rustc_session::{Session, EarlyErrorHandler};
30+
use rustc_session::Session;
3131
use std::cell::RefCell;
3232
use std::collections::HashMap;
3333
use std::thread_local;
@@ -58,7 +58,6 @@ impl rustc_driver::Callbacks for CompilerCalls {
5858
// the result.
5959
fn after_analysis<'tcx>(
6060
&mut self,
61-
_handler: &EarlyErrorHandler,
6261
compiler: &Compiler,
6362
queries: &'tcx Queries<'tcx>,
6463
) -> Compilation {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
include ../tools.mk
2+
3+
# Verify that the impl_* symbols are preserved. #108030
4+
# only-x86_64-unknown-linux-gnu
5+
# min-llvm-version: 17
6+
7+
all:
8+
$(RUSTC) -Cdebuginfo=0 -Copt-level=3 lib.rs
9+
$(RUSTC) -Clto=fat -Cdebuginfo=0 -Copt-level=3 main.rs
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#![crate_type = "rlib"]
2+
#![crate_type = "cdylib"]
3+
4+
#[macro_export]
5+
macro_rules! asm_func {
6+
($name:expr, $body:expr $(, $($args:tt)*)?) => {
7+
core::arch::global_asm!(
8+
concat!(
9+
".p2align 4\n",
10+
".hidden ", $name, "\n",
11+
".global ", $name, "\n",
12+
".type ", $name, ",@function\n",
13+
$name, ":\n",
14+
$body,
15+
".size ", $name, ",.-", $name,
16+
)
17+
$(, $($args)*)?
18+
);
19+
};
20+
}
21+
22+
macro_rules! libcall_trampoline {
23+
($libcall:ident ; $libcall_impl:ident) => {
24+
asm_func!(
25+
stringify!($libcall),
26+
concat!(
27+
"
28+
.cfi_startproc simple
29+
.cfi_def_cfa_offset 0
30+
jmp {}
31+
.cfi_endproc
32+
",
33+
),
34+
sym $libcall_impl
35+
);
36+
};
37+
}
38+
39+
pub mod trampolines {
40+
extern "C" {
41+
pub fn table_fill_funcref();
42+
pub fn table_fill_externref();
43+
}
44+
45+
unsafe extern "C" fn impl_table_fill_funcref() {}
46+
unsafe extern "C" fn impl_table_fill_externref() {}
47+
48+
libcall_trampoline!(table_fill_funcref ; impl_table_fill_funcref);
49+
libcall_trampoline!(table_fill_externref ; impl_table_fill_externref);
50+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
extern crate lib;
2+
3+
use lib::trampolines::*;
4+
5+
fn main() {
6+
unsafe {
7+
table_fill_externref();
8+
table_fill_funcref();
9+
}
10+
}

‎tests/ui-fulldeps/stable-mir/crate-info.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ fn test_stable_mir(tcx: TyCtxt<'_>) -> ControlFlow<()> {
154154
}
155155
}
156156

157+
let foo_const = get_item(tcx, &items, (DefKind::Const, "FOO")).unwrap();
158+
// Ensure we don't panic trying to get the body of a constant.
159+
foo_const.body();
160+
157161
ControlFlow::Continue(())
158162
}
159163

@@ -191,6 +195,8 @@ fn generate_input(path: &str) -> std::io::Result<()> {
191195
write!(
192196
file,
193197
r#"
198+
pub const FOO: u32 = 1 + 2;
199+
194200
fn generic<T, const U: usize>(t: T) -> [(); U] {{
195201
_ = t;
196202
[(); U]

‎tests/ui/abi/compatibility.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,21 +106,15 @@ test_transparent!(zst, Zst);
106106
test_transparent!(unit, ());
107107
test_transparent!(pair, (i32, f32)); // mixing in some floats since they often get special treatment
108108
test_transparent!(triple, (i8, i16, f32)); // chosen to fit into 64bit
109+
test_transparent!(triple_f32, (f32, f32, f32)); // homogeneous case
110+
test_transparent!(triple_f64, (f64, f64, f64));
109111
test_transparent!(tuple, (i32, f32, i64, f64));
110112
test_transparent!(empty_array, [u32; 0]);
111113
test_transparent!(empty_1zst_array, [u8; 0]);
112114
test_transparent!(small_array, [i32; 2]); // chosen to fit into 64bit
113115
test_transparent!(large_array, [i32; 16]);
114116
test_transparent!(enum_, Option<i32>);
115117
test_transparent!(enum_niched, Option<&'static i32>);
116-
// Pure-float types that are not ScalarPair seem to be tricky.
117-
// FIXME: <https://github.com/rust-lang/rust/issues/115664>
118-
#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
119-
mod tricky {
120-
use super::*;
121-
test_transparent!(triple_f32, (f32, f32, f32));
122-
test_transparent!(triple_f64, (f64, f64, f64));
123-
}
124118

125119
// RFC 3391 <https://rust-lang.github.io/rfcs/3391-result_ffi_guarantees.html>.
126120
macro_rules! test_nonnull {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#![feature(rustc_attrs)]
2+
#![feature(transparent_unions)]
3+
use std::marker::PhantomData;
4+
5+
// Regression test for #115664. We want to ensure that `repr(transparent)` wrappers do not affect
6+
// the result of `homogeneous_aggregate`.
7+
8+
type Tuple = (f32, f32, f32);
9+
10+
struct Zst;
11+
12+
#[repr(transparent)]
13+
struct Wrapper1<T>(T);
14+
#[repr(transparent)]
15+
struct Wrapper2<T>((), Zst, T);
16+
#[repr(transparent)]
17+
struct Wrapper3<T>(T, [u8; 0], PhantomData<u64>);
18+
#[repr(transparent)]
19+
union WrapperUnion<T: Copy> {
20+
nothing: (),
21+
something: T,
22+
}
23+
24+
#[rustc_layout(homogeneous_aggregate)]
25+
pub type Test0 = Tuple;
26+
//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
27+
28+
#[rustc_layout(homogeneous_aggregate)]
29+
pub type Test1 = Wrapper1<Tuple>;
30+
//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
31+
32+
#[rustc_layout(homogeneous_aggregate)]
33+
pub type Test2 = Wrapper2<Tuple>;
34+
//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
35+
36+
#[rustc_layout(homogeneous_aggregate)]
37+
pub type Test3 = Wrapper3<Tuple>;
38+
//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
39+
40+
#[rustc_layout(homogeneous_aggregate)]
41+
pub type Test4 = WrapperUnion<Tuple>;
42+
//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
43+
44+
fn main() {}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
2+
--> $DIR/homogeneous-aggr-transparent.rs:25:1
3+
|
4+
LL | pub type Test0 = Tuple;
5+
| ^^^^^^^^^^^^^^
6+
7+
error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
8+
--> $DIR/homogeneous-aggr-transparent.rs:29:1
9+
|
10+
LL | pub type Test1 = Wrapper1<Tuple>;
11+
| ^^^^^^^^^^^^^^
12+
13+
error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
14+
--> $DIR/homogeneous-aggr-transparent.rs:33:1
15+
|
16+
LL | pub type Test2 = Wrapper2<Tuple>;
17+
| ^^^^^^^^^^^^^^
18+
19+
error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
20+
--> $DIR/homogeneous-aggr-transparent.rs:37:1
21+
|
22+
LL | pub type Test3 = Wrapper3<Tuple>;
23+
| ^^^^^^^^^^^^^^
24+
25+
error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
26+
--> $DIR/homogeneous-aggr-transparent.rs:41:1
27+
|
28+
LL | pub type Test4 = WrapperUnion<Tuple>;
29+
| ^^^^^^^^^^^^^^
30+
31+
error: aborting due to 5 previous errors
32+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![deny(improper_ctypes_definitions)]
2+
3+
extern "C" fn foo<T: ?Sized + 'static>() -> Option<&'static T> {
4+
//~^ ERROR `extern` fn uses type `Option<&T>`, which is not FFI-safe
5+
None
6+
}
7+
8+
fn main() {}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: `extern` fn uses type `Option<&T>`, which is not FFI-safe
2+
--> $DIR/lint-ctypes-option-nonnull-unsized.rs:3:45
3+
|
4+
LL | extern "C" fn foo<T: ?Sized + 'static>() -> Option<&'static T> {
5+
| ^^^^^^^^^^^^^^^^^^ not FFI-safe
6+
|
7+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
8+
= note: enum has no representation hint
9+
note: the lint level is defined here
10+
--> $DIR/lint-ctypes-option-nonnull-unsized.rs:1:9
11+
|
12+
LL | #![deny(improper_ctypes_definitions)]
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
15+
error: aborting due to previous error
16+

0 commit comments

Comments
 (0)
Please sign in to comment.