Skip to content

Commit 46b180e

Browse files
committed
Auto merge of #122206 - matthiaskrgr:rollup-4txx9wx, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #121201 (align_offset, align_to: no longer allow implementations to spuriously fail to align) - #122076 (Tweak the way we protect in-place function arguments in interpreters) - #122100 (Better comment for implicit captures in RPITIT) - #122157 (Add the new description field to Target::to_json, and add descriptions for some MSVC targets) - #122164 (Fix misaligned loads when loading UEFI arg pointers) - #122171 (Add some new solver tests) - #122172 (Don't ICE if we collect no RPITITs unless there are no unification errors) - #122197 (inspect formatter: add braces) - #122198 (Remove handling for previously dropped LLVM version) r? `@ghost` `@rustbot` modify labels: rollup
2 parents a655e64 + b61edb9 commit 46b180e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+418
-214
lines changed

compiler/rustc_codegen_llvm/src/context.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -260,35 +260,29 @@ pub unsafe fn create_module<'ll>(
260260
}
261261

262262
if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
263-
let behavior = if llvm_version >= (15, 0, 0) {
264-
llvm::LLVMModFlagBehavior::Min
265-
} else {
266-
llvm::LLVMModFlagBehavior::Error
267-
};
268-
269263
if sess.target.arch == "aarch64" {
270264
llvm::LLVMRustAddModuleFlag(
271265
llmod,
272-
behavior,
266+
llvm::LLVMModFlagBehavior::Min,
273267
c"branch-target-enforcement".as_ptr().cast(),
274268
bti.into(),
275269
);
276270
llvm::LLVMRustAddModuleFlag(
277271
llmod,
278-
behavior,
272+
llvm::LLVMModFlagBehavior::Min,
279273
c"sign-return-address".as_ptr().cast(),
280274
pac_ret.is_some().into(),
281275
);
282276
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
283277
llvm::LLVMRustAddModuleFlag(
284278
llmod,
285-
behavior,
279+
llvm::LLVMModFlagBehavior::Min,
286280
c"sign-return-address-all".as_ptr().cast(),
287281
pac_opts.leaf.into(),
288282
);
289283
llvm::LLVMRustAddModuleFlag(
290284
llmod,
291-
behavior,
285+
llvm::LLVMModFlagBehavior::Min,
292286
c"sign-return-address-with-bkey".as_ptr().cast(),
293287
u32::from(pac_opts.key == PAuthKey::B),
294288
);

compiler/rustc_codegen_ssa/src/base.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -510,11 +510,13 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
510510
// Params for UEFI
511511
let param_handle = bx.get_param(0);
512512
let param_system_table = bx.get_param(1);
513+
let ptr_size = bx.tcx().data_layout.pointer_size;
514+
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
513515
let arg_argc = bx.const_int(cx.type_isize(), 2);
514-
let arg_argv = bx.alloca(cx.type_array(cx.type_ptr(), 2), Align::ONE);
515-
bx.store(param_handle, arg_argv, Align::ONE);
516-
let arg_argv_el1 = bx.gep(cx.type_ptr(), arg_argv, &[bx.const_int(cx.type_int(), 1)]);
517-
bx.store(param_system_table, arg_argv_el1, Align::ONE);
516+
let arg_argv = bx.alloca(cx.type_array(cx.type_ptr(), 2), ptr_align);
517+
bx.store(param_handle, arg_argv, ptr_align);
518+
let arg_argv_el1 = bx.inbounds_ptradd(arg_argv, bx.const_usize(ptr_size.bytes()));
519+
bx.store(param_system_table, arg_argv_el1, ptr_align);
518520
(arg_argc, arg_argv)
519521
} else if cx.sess().target.main_needs_argc_argv {
520522
// Params from native `main()` used as args for rust start function

compiler/rustc_const_eval/src/const_eval/machine.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
227227
if self.tcx.has_attr(def_id, sym::rustc_const_panic_str)
228228
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
229229
{
230-
let args = self.copy_fn_args(args)?;
230+
let args = self.copy_fn_args(args);
231231
// &str or &&str
232232
assert!(args.len() == 1);
233233

@@ -254,7 +254,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
254254

255255
return Ok(Some(new_instance));
256256
} else if Some(def_id) == self.tcx.lang_items().align_offset_fn() {
257-
let args = self.copy_fn_args(args)?;
257+
let args = self.copy_fn_args(args);
258258
// For align_offset, we replace the function call if the pointer has no address.
259259
match self.align_offset(instance, &args, dest, ret)? {
260260
ControlFlow::Continue(()) => return Ok(Some(instance)),

compiler/rustc_const_eval/src/interpret/machine.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -472,11 +472,11 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
472472
/// argument/return value was actually copied or passed in-place..
473473
fn protect_in_place_function_argument(
474474
ecx: &mut InterpCx<'mir, 'tcx, Self>,
475-
place: &PlaceTy<'tcx, Self::Provenance>,
475+
mplace: &MPlaceTy<'tcx, Self::Provenance>,
476476
) -> InterpResult<'tcx> {
477477
// Without an aliasing model, all we can do is put `Uninit` into the place.
478478
// Conveniently this also ensures that the place actually points to suitable memory.
479-
ecx.write_uninit(place)
479+
ecx.write_uninit(mplace)
480480
}
481481

482482
/// Called immediately before a new stack frame gets pushed.

compiler/rustc_const_eval/src/interpret/terminator.rs

+48-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::borrow::Cow;
22

3+
use either::Either;
4+
35
use rustc_middle::{
46
mir,
57
ty::{
@@ -29,28 +31,25 @@ pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
2931
Copy(OpTy<'tcx, Prov>),
3032
/// Allow for the argument to be passed in-place: destroy the value originally stored at that place and
3133
/// make the place inaccessible for the duration of the function call.
32-
InPlace(PlaceTy<'tcx, Prov>),
34+
InPlace(MPlaceTy<'tcx, Prov>),
3335
}
3436

3537
impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
3638
pub fn layout(&self) -> &TyAndLayout<'tcx> {
3739
match self {
3840
FnArg::Copy(op) => &op.layout,
39-
FnArg::InPlace(place) => &place.layout,
41+
FnArg::InPlace(mplace) => &mplace.layout,
4042
}
4143
}
4244
}
4345

4446
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
4547
/// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
4648
/// original memory occurs.
47-
pub fn copy_fn_arg(
48-
&self,
49-
arg: &FnArg<'tcx, M::Provenance>,
50-
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
49+
pub fn copy_fn_arg(&self, arg: &FnArg<'tcx, M::Provenance>) -> OpTy<'tcx, M::Provenance> {
5150
match arg {
52-
FnArg::Copy(op) => Ok(op.clone()),
53-
FnArg::InPlace(place) => self.place_to_op(place),
51+
FnArg::Copy(op) => op.clone(),
52+
FnArg::InPlace(mplace) => mplace.clone().into(),
5453
}
5554
}
5655

@@ -59,7 +58,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
5958
pub fn copy_fn_args(
6059
&self,
6160
args: &[FnArg<'tcx, M::Provenance>],
62-
) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::Provenance>>> {
61+
) -> Vec<OpTy<'tcx, M::Provenance>> {
6362
args.iter().map(|fn_arg| self.copy_fn_arg(fn_arg)).collect()
6463
}
6564

@@ -70,7 +69,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
7069
) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> {
7170
Ok(match arg {
7271
FnArg::Copy(op) => FnArg::Copy(self.project_field(op, field)?),
73-
FnArg::InPlace(place) => FnArg::InPlace(self.project_field(place, field)?),
72+
FnArg::InPlace(mplace) => FnArg::InPlace(self.project_field(mplace, field)?),
7473
})
7574
}
7675

@@ -238,10 +237,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
238237
) -> InterpResult<'tcx, Vec<FnArg<'tcx, M::Provenance>>> {
239238
ops.iter()
240239
.map(|op| {
241-
Ok(match &op.node {
242-
mir::Operand::Move(place) => FnArg::InPlace(self.eval_place(*place)?),
243-
_ => FnArg::Copy(self.eval_operand(&op.node, None)?),
244-
})
240+
let arg = match &op.node {
241+
mir::Operand::Copy(_) | mir::Operand::Constant(_) => {
242+
// Make a regular copy.
243+
let op = self.eval_operand(&op.node, None)?;
244+
FnArg::Copy(op)
245+
}
246+
mir::Operand::Move(place) => {
247+
// If this place lives in memory, preserve its location.
248+
// We call `place_to_op` which will be an `MPlaceTy` whenever there exists
249+
// an mplace for this place. (This is in contrast to `PlaceTy::as_mplace_or_local`
250+
// which can return a local even if that has an mplace.)
251+
let place = self.eval_place(*place)?;
252+
let op = self.place_to_op(&place)?;
253+
254+
match op.as_mplace_or_imm() {
255+
Either::Left(mplace) => FnArg::InPlace(mplace),
256+
Either::Right(_imm) => {
257+
// This argument doesn't live in memory, so there's no place
258+
// to make inaccessible during the call.
259+
// We rely on there not being any stray `PlaceTy` that would let the
260+
// caller directly access this local!
261+
// This is also crucial for tail calls, where we want the `FnArg` to
262+
// stay valid when the old stack frame gets popped.
263+
FnArg::Copy(op)
264+
}
265+
}
266+
}
267+
};
268+
269+
Ok(arg)
245270
})
246271
.collect()
247272
}
@@ -451,7 +476,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
451476
// We work with a copy of the argument for now; if this is in-place argument passing, we
452477
// will later protect the source it comes from. This means the callee cannot observe if we
453478
// did in-place of by-copy argument passing, except for pointer equality tests.
454-
let caller_arg_copy = self.copy_fn_arg(caller_arg)?;
479+
let caller_arg_copy = self.copy_fn_arg(caller_arg);
455480
if !already_live {
456481
let local = callee_arg.as_local().unwrap();
457482
let meta = caller_arg_copy.meta();
@@ -469,8 +494,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
469494
// specifically.)
470495
self.copy_op_allow_transmute(&caller_arg_copy, &callee_arg)?;
471496
// If this was an in-place pass, protect the place it comes from for the duration of the call.
472-
if let FnArg::InPlace(place) = caller_arg {
473-
M::protect_in_place_function_argument(self, place)?;
497+
if let FnArg::InPlace(mplace) = caller_arg {
498+
M::protect_in_place_function_argument(self, mplace)?;
474499
}
475500
Ok(())
476501
}
@@ -517,7 +542,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
517542
M::call_intrinsic(
518543
self,
519544
instance,
520-
&self.copy_fn_args(args)?,
545+
&self.copy_fn_args(args),
521546
destination,
522547
target,
523548
unwind,
@@ -594,8 +619,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
594619
.map(|arg| (
595620
arg.layout().ty,
596621
match arg {
597-
FnArg::Copy(op) => format!("copy({:?})", *op),
598-
FnArg::InPlace(place) => format!("in-place({:?})", *place),
622+
FnArg::Copy(op) => format!("copy({op:?})"),
623+
FnArg::InPlace(mplace) => format!("in-place({mplace:?})"),
599624
}
600625
))
601626
.collect::<Vec<_>>()
@@ -717,8 +742,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
717742
callee_ty: callee_fn_abi.ret.layout.ty
718743
});
719744
}
745+
720746
// Protect return place for in-place return value passing.
721-
M::protect_in_place_function_argument(self, &destination.clone().into())?;
747+
M::protect_in_place_function_argument(self, &destination)?;
722748

723749
// Don't forget to mark "initially live" locals as live.
724750
self.storage_live_for_always_live_locals()?;
@@ -741,7 +767,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
741767
// An `InPlace` does nothing here, we keep the original receiver intact. We can't
742768
// really pass the argument in-place anyway, and we are constructing a new
743769
// `Immediate` receiver.
744-
let mut receiver = self.copy_fn_arg(&args[0])?;
770+
let mut receiver = self.copy_fn_arg(&args[0]);
745771
let receiver_place = loop {
746772
match receiver.layout.ty.kind() {
747773
ty::Ref(..) | ty::RawPtr(..) => {
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,26 @@
1-
A lifetime bound on a trait implementation was captured at an incorrect place.
1+
An `impl Trait` captured a higher-ranked lifetime, which is not supported.
2+
3+
Currently, `impl Trait` types are only allowed to capture lifetimes from
4+
their parent items, and not from any `for<'a>` binders in scope.
25

36
Erroneous code example:
47

58
```compile_fail,E0657
6-
trait Id<T> {}
7-
trait Lt<'a> {}
8-
9-
impl<'a> Lt<'a> for () {}
10-
impl<T> Id<T> for T {}
11-
12-
fn free_fn_capture_hrtb_in_impl_trait()
13-
-> Box<for<'a> Id<impl Lt<'a>>> // error!
14-
{
15-
Box::new(())
16-
}
9+
trait BorrowInto<'a> {
10+
type Target;
1711
18-
struct Foo;
19-
impl Foo {
20-
fn impl_fn_capture_hrtb_in_impl_trait()
21-
-> Box<for<'a> Id<impl Lt<'a>>> // error!
22-
{
23-
Box::new(())
24-
}
12+
fn borrow_into(&'a self) -> Self::Target;
2513
}
26-
```
2714
28-
Here, you have used the inappropriate lifetime in the `impl Trait`,
29-
The `impl Trait` can only capture lifetimes bound at the fn or impl
30-
level.
15+
impl<'a> BorrowInto<'a> for () {
16+
type Target = &'a ();
3117
32-
To fix this we have to define the lifetime at the function or impl
33-
level and use that lifetime in the `impl Trait`. For example you can
34-
define the lifetime at the function:
35-
36-
```
37-
trait Id<T> {}
38-
trait Lt<'a> {}
39-
40-
impl<'a> Lt<'a> for () {}
41-
impl<T> Id<T> for T {}
42-
43-
fn free_fn_capture_hrtb_in_impl_trait<'b>()
44-
-> Box<for<'a> Id<impl Lt<'b>>> // ok!
45-
{
46-
Box::new(())
18+
fn borrow_into(&'a self) -> Self::Target {
19+
self
20+
}
4721
}
4822
49-
struct Foo;
50-
impl Foo {
51-
fn impl_fn_capture_hrtb_in_impl_trait<'b>()
52-
-> Box<for<'a> Id<impl Lt<'b>>> // ok!
53-
{
54-
Box::new(())
55-
}
23+
fn opaque() -> impl for<'a> BorrowInto<'a, Target = impl Sized + 'a> {
24+
()
5625
}
5726
```

compiler/rustc_hir_analysis/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ hir_analysis_only_current_traits_primitive = only traits defined in the current
312312
313313
hir_analysis_only_current_traits_ty = `{$ty}` is not defined in the current crate
314314
315+
hir_analysis_opaque_captures_higher_ranked_lifetime = `impl Trait` cannot capture {$bad_place}
316+
.label = `impl Trait` implicitly captures all lifetimes in scope
317+
.note = lifetime declared here
318+
315319
hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
316320
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
317321

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -521,14 +521,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
521521
)
522522
.fold_with(&mut collector);
523523

524-
if !unnormalized_trait_sig.output().references_error() {
525-
debug_assert_ne!(
526-
collector.types.len(),
527-
0,
528-
"expect >1 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`"
529-
);
530-
}
531-
532524
let trait_sig = ocx.normalize(&misc_cause, param_env, unnormalized_trait_sig);
533525
trait_sig.error_reported()?;
534526
let trait_return_ty = trait_sig.output();
@@ -647,6 +639,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
647639
}
648640
}
649641

642+
if !unnormalized_trait_sig.output().references_error() {
643+
debug_assert!(
644+
!collector.types.is_empty(),
645+
"expect >0 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`"
646+
);
647+
}
648+
650649
// FIXME: This has the same issue as #108544, but since this isn't breaking
651650
// existing code, I'm not particularly inclined to do the same hack as above
652651
// where we process wf obligations manually. This can be fixed in a forward-

0 commit comments

Comments
 (0)