Skip to content

Commit 2d76d9b

Browse files
committed
Auto merge of #153617 - JonathanBrouwer:rollup-udG4Tzr, r=JonathanBrouwer
Rollup of 4 pull requests Successful merges: - #147834 (Always make tuple elements a coercion site) - #150446 (miri/const eval: support `MaybeDangling`) - #153053 (stop marking `deref_patterns` as an incomplete feature) - #153398 (fix ICE in `const_c_variadic` when passing ZSTs)
2 parents 3945997 + 610ea1d commit 2d76d9b

64 files changed

Lines changed: 344 additions & 149 deletions

File tree

Some content is hidden

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

compiler/rustc_const_eval/src/interpret/call.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_hir::find_attr;
1212
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
1313
use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};
1414
use rustc_middle::{bug, mir, span_bug};
15-
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
15+
use rustc_target::callconv::{ArgAbi, FnAbi};
1616
use tracing::field::Empty;
1717
use tracing::{info, instrument, trace};
1818

@@ -284,7 +284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
284284
'tcx: 'y,
285285
{
286286
assert_eq!(callee_ty, callee_abi.layout.ty);
287-
if callee_abi.mode == PassMode::Ignore {
287+
if callee_abi.is_ignore() {
288288
// This one is skipped. Still must be made live though!
289289
if !already_live {
290290
self.storage_live(callee_arg.as_local().unwrap())?;
@@ -450,7 +450,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
450450
let mut caller_args = args
451451
.iter()
452452
.zip(caller_fn_abi.args.iter())
453-
.filter(|arg_and_abi| !matches!(arg_and_abi.1.mode, PassMode::Ignore));
453+
.filter(|arg_and_abi| !arg_and_abi.1.is_ignore());
454454

455455
// Now we have to spread them out across the callee's locals,
456456
// taking into account the `spread_arg`. If we could write
@@ -480,7 +480,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
480480

481481
// Consume the remaining arguments by putting them into the variable argument
482482
// list.
483-
let varargs = self.allocate_varargs(&mut caller_args, &mut callee_args_abis)?;
483+
let varargs = self.allocate_varargs(
484+
&mut caller_args,
485+
// "Ignored" arguments aren't actually passed, so the callee should also
486+
// ignore them. (`pass_argument` does this for regular arguments.)
487+
(&mut callee_args_abis).filter(|(_, abi)| !abi.is_ignore()),
488+
)?;
484489
// When the frame is dropped, these variable arguments are deallocated.
485490
self.frame_mut().va_list = varargs.clone();
486491
let key = self.va_list_ptr(varargs.into());

compiler/rustc_const_eval/src/interpret/stack.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -631,8 +631,8 @@ impl<'a, 'tcx: 'a, M: Machine<'tcx>> InterpCx<'tcx, M> {
631631
/// of variadic arguments. Return a list of the places that hold those arguments.
632632
pub(crate) fn allocate_varargs<I, J>(
633633
&mut self,
634-
caller_args: &mut I,
635-
callee_abis: &mut J,
634+
caller_args: I,
635+
mut callee_abis: J,
636636
) -> InterpResult<'tcx, Vec<MPlaceTy<'tcx, M::Provenance>>>
637637
where
638638
I: Iterator<Item = (&'a FnArg<'tcx, M::Provenance>, &'a ArgAbi<'tcx, Ty<'tcx>>)>,

compiler/rustc_const_eval/src/interpret/validity.rs

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use std::borrow::Cow;
88
use std::fmt::Write;
99
use std::hash::Hash;
10+
use std::mem;
1011
use std::num::NonZero;
1112

1213
use either::{Left, Right};
@@ -288,6 +289,8 @@ struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> {
288289
/// If this is `Some`, then `reset_provenance_and_padding` must be true (but not vice versa:
289290
/// we might not track data vs padding bytes if the operand isn't stored in memory anyway).
290291
data_bytes: Option<RangeSet>,
292+
/// True if we are inside of `MaybeDangling`. This disables pointer access checks.
293+
may_dangle: bool,
291294
}
292295

293296
impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
@@ -489,7 +492,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
489492
if place.layout.is_unsized() {
490493
self.check_wide_ptr_meta(place.meta(), place.layout)?;
491494
}
492-
// Make sure this is dereferenceable and all.
495+
496+
// Determine size and alignment of pointee.
493497
let size_and_align = try_validation!(
494498
self.ecx.size_and_align_of_val(&place),
495499
self.path,
@@ -503,27 +507,33 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
503507
// alignment and size determined by the layout (size will be 0,
504508
// alignment should take attributes into account).
505509
.unwrap_or_else(|| (place.layout.size, place.layout.align.abi));
506-
// Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
507-
try_validation!(
508-
self.ecx.check_ptr_access(
509-
place.ptr(),
510-
size,
511-
CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message
512-
),
513-
self.path,
514-
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind, maybe: false },
515-
Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
516-
ptr_kind,
517-
// FIXME this says "null pointer" when null but we need translate
518-
pointer: format!("{}", Pointer::<Option<AllocId>>::without_provenance(i))
519-
},
520-
Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds {
521-
ptr_kind
522-
},
523-
Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree {
524-
ptr_kind,
525-
},
526-
);
510+
511+
if !self.may_dangle {
512+
// Make sure this is dereferenceable and all.
513+
514+
// Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
515+
// Call `check_ptr_access` to avoid checking alignment here.
516+
try_validation!(
517+
self.ecx.check_ptr_access(
518+
place.ptr(),
519+
size,
520+
CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message
521+
),
522+
self.path,
523+
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind, maybe: false },
524+
Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
525+
ptr_kind,
526+
pointer: format!("{}", Pointer::<Option<AllocId>>::without_provenance(i))
527+
},
528+
Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds {
529+
ptr_kind
530+
},
531+
Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree {
532+
ptr_kind,
533+
},
534+
);
535+
}
536+
527537
try_validation!(
528538
self.ecx.check_ptr_align(
529539
place.ptr(),
@@ -536,8 +546,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
536546
found_bytes: has.bytes()
537547
},
538548
);
539-
// Make sure this is non-null. We checked dereferenceability above, but if `size` is zero
540-
// that does not imply non-null.
549+
550+
// Make sure this is non-null. This is obviously needed when `may_dangle` is set,
551+
// but even if we did check dereferenceability above that would still allow null
552+
// pointers if `size` is zero.
541553
let scalar = Scalar::from_maybe_pointer(place.ptr(), self.ecx);
542554
if self.ecx.scalar_may_be_null(scalar)? {
543555
let maybe = !M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..));
@@ -1265,6 +1277,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
12651277
ty::PatternKind::Or(_patterns) => {}
12661278
}
12671279
}
1280+
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
1281+
let old_may_dangle = mem::replace(&mut self.may_dangle, true);
1282+
1283+
let inner = self.ecx.project_field(val, FieldIdx::ZERO)?;
1284+
self.visit_value(&inner)?;
1285+
1286+
self.may_dangle = old_may_dangle;
1287+
}
12681288
_ => {
12691289
// default handler
12701290
try_validation!(
@@ -1350,6 +1370,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
13501370
ecx,
13511371
reset_provenance_and_padding,
13521372
data_bytes: reset_padding.then_some(RangeSet(Vec::new())),
1373+
may_dangle: false,
13531374
};
13541375
v.visit_value(val)?;
13551376
v.reset_padding(val)?;

compiler/rustc_feature/src/unstable.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ declare_features! (
465465
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
466466
(unstable, deprecated_suggestion, "1.61.0", Some(94785)),
467467
/// Allows deref patterns.
468-
(incomplete, deref_patterns, "1.79.0", Some(87121)),
468+
(unstable, deref_patterns, "1.79.0", Some(87121)),
469469
/// Allows deriving the From trait on single-field structs.
470470
(unstable, derive_from, "1.91.0", Some(144889)),
471471
/// Allows giving non-const impls custom diagnostic messages if attempted to be used as const

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,27 +1792,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17921792

17931793
fn check_expr_tuple(
17941794
&self,
1795-
elts: &'tcx [hir::Expr<'tcx>],
1795+
elements: &'tcx [hir::Expr<'tcx>],
17961796
expected: Expectation<'tcx>,
17971797
expr: &'tcx hir::Expr<'tcx>,
17981798
) -> Ty<'tcx> {
1799-
let flds = expected.only_has_type(self).and_then(|ty| {
1800-
let ty = self.try_structurally_resolve_type(expr.span, ty);
1801-
match ty.kind() {
1802-
ty::Tuple(flds) => Some(&flds[..]),
1803-
_ => None,
1804-
}
1799+
let mut expectations = expected
1800+
.only_has_type(self)
1801+
.and_then(|ty| self.try_structurally_resolve_type(expr.span, ty).opt_tuple_fields())
1802+
.unwrap_or_default()
1803+
.iter();
1804+
1805+
let elements = elements.iter().map(|e| {
1806+
let ty = expectations.next().unwrap_or_else(|| self.next_ty_var(e.span));
1807+
self.check_expr_coercible_to_type(e, ty, None);
1808+
ty
18051809
});
18061810

1807-
let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds {
1808-
Some(fs) if i < fs.len() => {
1809-
let ety = fs[i];
1810-
self.check_expr_coercible_to_type(e, ety, None);
1811-
ety
1812-
}
1813-
_ => self.check_expr_with_expectation(e, NoExpectation),
1814-
});
1815-
let tuple = Ty::new_tup_from_iter(self.tcx, elt_ts_iter);
1811+
let tuple = Ty::new_tup_from_iter(self.tcx, elements);
1812+
18161813
if let Err(guar) = tuple.error_reported() {
18171814
Ty::new_error(self.tcx, guar)
18181815
} else {

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1592,7 +1592,8 @@ impl<'tcx> Ty<'tcx> {
15921592
}
15931593
}
15941594

1595-
/// Iterates over tuple fields.
1595+
/// Returns a list of tuple type arguments.
1596+
///
15961597
/// Panics when called on anything but a tuple.
15971598
#[inline]
15981599
pub fn tuple_fields(self) -> &'tcx List<Ty<'tcx>> {
@@ -1602,6 +1603,15 @@ impl<'tcx> Ty<'tcx> {
16021603
}
16031604
}
16041605

1606+
/// Returns a list of tuple type arguments, or `None` if `self` isn't a tuple.
1607+
#[inline]
1608+
pub fn opt_tuple_fields(self) -> Option<&'tcx List<Ty<'tcx>>> {
1609+
match self.kind() {
1610+
Tuple(args) => Some(args),
1611+
_ => None,
1612+
}
1613+
}
1614+
16051615
/// If the type contains variants, returns the valid range of variant indices.
16061616
//
16071617
// FIXME: This requires the optimized MIR in the case of coroutines.

src/doc/unstable-book/src/language-features/deref-patterns.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,14 @@ The tracking issue for this feature is: [#87121]
66

77
------------------------
88

9-
> **Note**: This feature is incomplete. In the future, it is meant to supersede
10-
> [`box_patterns`].
9+
> **Note**: This feature supersedes [`box_patterns`].
1110
1211
This feature permits pattern matching on [smart pointers in the standard library] through their
1312
`Deref` target types, either implicitly or with explicit `deref!(_)` patterns (the syntax of which
1413
is currently a placeholder).
1514

1615
```rust
1716
#![feature(deref_patterns)]
18-
#![allow(incomplete_features)]
1917

2018
let mut v = vec![Box::new(Some(0))];
2119

@@ -58,7 +56,6 @@ Like [`box_patterns`], deref patterns may move out of boxes:
5856

5957
```rust
6058
# #![feature(deref_patterns)]
61-
# #![allow(incomplete_features)]
6259
struct NoCopy;
6360
let deref!(x) = Box::new(NoCopy);
6461
drop::<NoCopy>(x);
@@ -69,7 +66,6 @@ allowing then to be used in deref patterns:
6966

7067
```rust
7168
# #![feature(deref_patterns)]
72-
# #![allow(incomplete_features)]
7369
match ("test".to_string(), Box::from("test"), b"test".to_vec()) {
7470
("test", "test", b"test") => {}
7571
_ => panic!(),

src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
917917
RetagInfo { cause: self.retag_cause, in_field: self.in_field },
918918
)?;
919919
self.ecx.write_immediate(*val, place)?;
920+
920921
interp_ok(())
921922
}
922923
}
@@ -964,6 +965,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
964965
// even if field retagging is not enabled. *shrug*)
965966
self.walk_value(place)?;
966967
}
968+
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
969+
// Skip traversing for everything inside of `MaybeDangling`
970+
}
967971
_ => {
968972
// Not a reference/pointer/box. Recurse.
969973
let in_field = mem::replace(&mut self.in_field, true); // remember and restore old value

src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
523523
// even if field retagging is not enabled. *shrug*)
524524
self.walk_value(place)?;
525525
}
526+
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
527+
// Skip traversing for everything inside of `MaybeDangling`
528+
}
526529
_ => {
527530
// Not a reference/pointer/box. Recurse.
528531
self.walk_value(place)?;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Test that an unaligned `MaybeDangling<&u8>` is still detected as UB.
2+
//
3+
//@compile-flags: -Zmiri-disable-stacked-borrows
4+
#![feature(maybe_dangling)]
5+
6+
use std::mem::{MaybeDangling, transmute};
7+
8+
fn main() {
9+
let a = [1u16, 0u16];
10+
unsafe {
11+
let unaligned = MaybeDangling::new(a.as_ptr().byte_add(1));
12+
transmute::<MaybeDangling<*const u16>, MaybeDangling<&u16>>(unaligned)
13+
//~^ ERROR: Undefined Behavior: constructing invalid value: encountered an unaligned reference
14+
};
15+
}

0 commit comments

Comments
 (0)