Skip to content

Commit 50cf76c

Browse files
committed
Auto merge of rust-lang#96734 - matthiaskrgr:rollup-hng33tb, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - rust-lang#95359 (Update `int_roundings` methods from feedback) - rust-lang#95843 (Improve Rc::new_cyclic and Arc::new_cyclic documentation) - rust-lang#96507 (Suggest calling `Self::associated_function()`) - rust-lang#96635 (Use "strict" mode in JS scripts) - rust-lang#96673 (Report that opaque types are not allowed in impls even in the presence of other errors) - rust-lang#96682 (Show invisible delimeters (within comments) when pretty printing.) - rust-lang#96714 (interpret/validity: debug-check ScalarPair layout information) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents a7d6768 + 6804819 commit 50cf76c

Some content is hidden

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

53 files changed

+522
-258
lines changed

compiler/rustc_ast/src/token.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@ pub enum Delimiter {
5050
Brace,
5151
/// `[ ... ]`
5252
Bracket,
53-
/// `Ø ... Ø`
53+
/// `/*«*/ ... /*»*/`
5454
/// An invisible delimiter, that may, for example, appear around tokens coming from a
5555
/// "macro variable" `$var`. It is important to preserve operator priorities in cases like
5656
/// `$var * 3` where `$var` is `1 + 2`.
57-
/// Invisible delimiters might not survive roundtrip of a token stream through a string.
57+
/// Invisible delimiters are not directly writable in normal Rust code except as comments.
58+
/// Therefore, they might not survive a roundtrip of a token stream through a string.
5859
Invisible,
5960
}
6061

compiler/rustc_ast_pretty/src/pprust/state.rs

+18-5
Original file line numberDiff line numberDiff line change
@@ -590,15 +590,29 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
590590
self.nbsp();
591591
}
592592
self.word("{");
593-
if !tts.is_empty() {
593+
let empty = tts.is_empty();
594+
if !empty {
594595
self.space();
595596
}
596597
self.ibox(0);
597598
self.print_tts(tts, convert_dollar_crate);
598599
self.end();
599-
let empty = tts.is_empty();
600600
self.bclose(span, empty);
601601
}
602+
Some(Delimiter::Invisible) => {
603+
self.word("/*«*/");
604+
let empty = tts.is_empty();
605+
if !empty {
606+
self.space();
607+
}
608+
self.ibox(0);
609+
self.print_tts(tts, convert_dollar_crate);
610+
self.end();
611+
if !empty {
612+
self.space();
613+
}
614+
self.word("/*»*/");
615+
}
602616
Some(delim) => {
603617
let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
604618
self.word(token_str);
@@ -772,9 +786,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
772786
token::CloseDelim(Delimiter::Bracket) => "]".into(),
773787
token::OpenDelim(Delimiter::Brace) => "{".into(),
774788
token::CloseDelim(Delimiter::Brace) => "}".into(),
775-
token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => {
776-
"".into()
777-
}
789+
token::OpenDelim(Delimiter::Invisible) => "/*«*/".into(),
790+
token::CloseDelim(Delimiter::Invisible) => "/*»*/".into(),
778791
token::Pound => "#".into(),
779792
token::Dollar => "$".into(),
780793
token::Question => "?".into(),

compiler/rustc_const_eval/src/interpret/operand.rs

+55-29
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,18 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> {
8484
}
8585

8686
#[inline]
87-
pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> {
87+
pub fn to_scalar_or_uninit_pair(self) -> (ScalarMaybeUninit<Tag>, ScalarMaybeUninit<Tag>) {
8888
match self {
89-
Immediate::ScalarPair(val1, val2) => Ok((val1.check_init()?, val2.check_init()?)),
90-
Immediate::Scalar(..) => {
91-
bug!("Got a scalar where a scalar pair was expected")
92-
}
89+
Immediate::ScalarPair(val1, val2) => (val1, val2),
90+
Immediate::Scalar(..) => bug!("Got a scalar where a scalar pair was expected"),
9391
}
9492
}
93+
94+
#[inline]
95+
pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> {
96+
let (val1, val2) = self.to_scalar_or_uninit_pair();
97+
Ok((val1.check_init()?, val2.check_init()?))
98+
}
9599
}
96100

97101
// ScalarPair needs a type to interpret, so we often have an immediate and a type together
@@ -248,9 +252,12 @@ impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> {
248252
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
249253
/// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`.
250254
/// Returns `None` if the layout does not permit loading this as a value.
251-
fn try_read_immediate_from_mplace(
255+
///
256+
/// This is an internal function; call `read_immediate` instead.
257+
fn read_immediate_from_mplace_raw(
252258
&self,
253259
mplace: &MPlaceTy<'tcx, M::PointerTag>,
260+
force: bool,
254261
) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::PointerTag>>> {
255262
if mplace.layout.is_unsized() {
256263
// Don't touch unsized
@@ -271,42 +278,61 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
271278
// case where some of the bytes are initialized and others are not. So, we need an extra
272279
// check that walks over the type of `mplace` to make sure it is truly correct to treat this
273280
// like a `Scalar` (or `ScalarPair`).
274-
match mplace.layout.abi {
275-
Abi::Scalar(abi::Scalar::Initialized { .. }) => {
276-
let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?;
277-
Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout }))
278-
}
281+
let scalar_layout = match mplace.layout.abi {
282+
// `if` does not work nested inside patterns, making this a bit awkward to express.
283+
Abi::Scalar(abi::Scalar::Initialized { value: s, .. }) => Some(s),
284+
Abi::Scalar(s) if force => Some(s.primitive()),
285+
_ => None,
286+
};
287+
if let Some(_) = scalar_layout {
288+
let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?;
289+
return Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout }));
290+
}
291+
let scalar_pair_layout = match mplace.layout.abi {
279292
Abi::ScalarPair(
280293
abi::Scalar::Initialized { value: a, .. },
281294
abi::Scalar::Initialized { value: b, .. },
282-
) => {
283-
// We checked `ptr_align` above, so all fields will have the alignment they need.
284-
// We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
285-
// which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
286-
let (a_size, b_size) = (a.size(self), b.size(self));
287-
let b_offset = a_size.align_to(b.align(self).abi);
288-
assert!(b_offset.bytes() > 0); // we later use the offset to tell apart the fields
289-
let a_val = alloc.read_scalar(alloc_range(Size::ZERO, a_size))?;
290-
let b_val = alloc.read_scalar(alloc_range(b_offset, b_size))?;
291-
Ok(Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout }))
292-
}
293-
_ => Ok(None),
295+
) => Some((a, b)),
296+
Abi::ScalarPair(a, b) if force => Some((a.primitive(), b.primitive())),
297+
_ => None,
298+
};
299+
if let Some((a, b)) = scalar_pair_layout {
300+
// We checked `ptr_align` above, so all fields will have the alignment they need.
301+
// We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
302+
// which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
303+
let (a_size, b_size) = (a.size(self), b.size(self));
304+
let b_offset = a_size.align_to(b.align(self).abi);
305+
assert!(b_offset.bytes() > 0); // we later use the offset to tell apart the fields
306+
let a_val = alloc.read_scalar(alloc_range(Size::ZERO, a_size))?;
307+
let b_val = alloc.read_scalar(alloc_range(b_offset, b_size))?;
308+
return Ok(Some(ImmTy {
309+
imm: Immediate::ScalarPair(a_val, b_val),
310+
layout: mplace.layout,
311+
}));
294312
}
313+
// Neither a scalar nor scalar pair.
314+
return Ok(None);
295315
}
296316

297-
/// Try returning an immediate for the operand.
298-
/// If the layout does not permit loading this as an immediate, return where in memory
299-
/// we can find the data.
317+
/// Try returning an immediate for the operand. If the layout does not permit loading this as an
318+
/// immediate, return where in memory we can find the data.
300319
/// Note that for a given layout, this operation will either always fail or always
301320
/// succeed! Whether it succeeds depends on whether the layout can be represented
302321
/// in an `Immediate`, not on which data is stored there currently.
303-
pub fn try_read_immediate(
322+
///
323+
/// If `force` is `true`, then even scalars with fields that can be ununit will be
324+
/// read. This means the load is lossy and should not be written back!
325+
/// This flag exists only for validity checking.
326+
///
327+
/// This is an internal function that should not usually be used; call `read_immediate` instead.
328+
pub fn read_immediate_raw(
304329
&self,
305330
src: &OpTy<'tcx, M::PointerTag>,
331+
force: bool,
306332
) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::PointerTag>, MPlaceTy<'tcx, M::PointerTag>>> {
307333
Ok(match src.try_as_mplace() {
308334
Ok(ref mplace) => {
309-
if let Some(val) = self.try_read_immediate_from_mplace(mplace)? {
335+
if let Some(val) = self.read_immediate_from_mplace_raw(mplace, force)? {
310336
Ok(val)
311337
} else {
312338
Err(*mplace)
@@ -322,7 +348,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
322348
&self,
323349
op: &OpTy<'tcx, M::PointerTag>,
324350
) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
325-
if let Ok(imm) = self.try_read_immediate(op)? {
351+
if let Ok(imm) = self.read_immediate_raw(op, /*force*/ false)? {
326352
Ok(imm)
327353
} else {
328354
span_bug!(self.cur_span(), "primitive read failed for type: {:?}", op.layout.ty);

compiler/rustc_const_eval/src/interpret/place.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ where
720720
}
721721
trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
722722

723-
// See if we can avoid an allocation. This is the counterpart to `try_read_immediate`,
723+
// See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`,
724724
// but not factored as a separate function.
725725
let mplace = match dest.place {
726726
Place::Local { frame, local } => {
@@ -879,7 +879,7 @@ where
879879
}
880880

881881
// Let us see if the layout is simple so we take a shortcut, avoid force_allocation.
882-
let src = match self.try_read_immediate(src)? {
882+
let src = match self.read_immediate_raw(src, /*force*/ false)? {
883883
Ok(src_val) => {
884884
assert!(!src.layout.is_unsized(), "cannot have unsized immediates");
885885
// Yay, we got a value that we can write directly.

compiler/rustc_const_eval/src/interpret/validity.rs

+38-18
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use rustc_target::abi::{Abi, Scalar as ScalarAbi, Size, VariantIdx, Variants, Wr
2020
use std::hash::Hash;
2121

2222
use super::{
23-
alloc_range, CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine,
24-
MemPlaceMeta, OpTy, Scalar, ScalarMaybeUninit, ValueVisitor,
23+
alloc_range, CheckInAllocMsg, GlobalAlloc, Immediate, InterpCx, InterpResult, MPlaceTy,
24+
Machine, MemPlaceMeta, OpTy, Scalar, ScalarMaybeUninit, ValueVisitor,
2525
};
2626

2727
macro_rules! throw_validation_failure {
@@ -487,6 +487,17 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
487487
))
488488
}
489489

490+
fn read_immediate_forced(
491+
&self,
492+
op: &OpTy<'tcx, M::PointerTag>,
493+
) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
494+
Ok(*try_validation!(
495+
self.ecx.read_immediate_raw(op, /*force*/ true),
496+
self.path,
497+
err_unsup!(ReadPointerAsBytes) => { "(potentially part of) a pointer" } expected { "plain (non-pointer) bytes" },
498+
).unwrap())
499+
}
500+
490501
/// Check if this is a value of primitive type, and if yes check the validity of the value
491502
/// at that type. Return `true` if the type is indeed primitive.
492503
fn try_visit_primitive(
@@ -626,18 +637,19 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
626637

627638
fn visit_scalar(
628639
&mut self,
629-
op: &OpTy<'tcx, M::PointerTag>,
640+
scalar: ScalarMaybeUninit<M::PointerTag>,
630641
scalar_layout: ScalarAbi,
631642
) -> InterpResult<'tcx> {
632643
// We check `is_full_range` in a slightly complicated way because *if* we are checking
633644
// number validity, then we want to ensure that `Scalar::Initialized` is indeed initialized,
634645
// i.e. that we go over the `check_init` below.
646+
let size = scalar_layout.size(self.ecx);
635647
let is_full_range = match scalar_layout {
636648
ScalarAbi::Initialized { valid_range, .. } => {
637649
if M::enforce_number_validity(self.ecx) {
638650
false // not "full" since uninit is not accepted
639651
} else {
640-
valid_range.is_full_for(op.layout.size)
652+
valid_range.is_full_for(size)
641653
}
642654
}
643655
ScalarAbi::Union { .. } => true,
@@ -646,21 +658,19 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
646658
// Nothing to check
647659
return Ok(());
648660
}
649-
// We have something to check.
661+
// We have something to check: it must at least be initialized.
650662
let valid_range = scalar_layout.valid_range(self.ecx);
651663
let WrappingRange { start, end } = valid_range;
652-
let max_value = op.layout.size.unsigned_int_max();
664+
let max_value = size.unsigned_int_max();
653665
assert!(end <= max_value);
654-
// Determine the allowed range
655-
let value = self.read_scalar(op)?;
656666
let value = try_validation!(
657-
value.check_init(),
667+
scalar.check_init(),
658668
self.path,
659-
err_ub!(InvalidUninitBytes(None)) => { "{:x}", value }
669+
err_ub!(InvalidUninitBytes(None)) => { "{:x}", scalar }
660670
expected { "something {}", wrapping_range_format(valid_range, max_value) },
661671
);
662672
let bits = match value.try_to_int() {
663-
Ok(int) => int.assert_bits(op.layout.size),
673+
Ok(int) => int.assert_bits(size),
664674
Err(_) => {
665675
// So this is a pointer then, and casting to an int failed.
666676
// Can only happen during CTFE.
@@ -678,7 +688,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
678688
} else {
679689
return Ok(());
680690
}
681-
} else if scalar_layout.valid_range(self.ecx).is_full_for(op.layout.size) {
691+
} else if scalar_layout.valid_range(self.ecx).is_full_for(size) {
682692
// Easy. (This is reachable if `enforce_number_validity` is set.)
683693
return Ok(());
684694
} else {
@@ -817,13 +827,23 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
817827
);
818828
}
819829
Abi::Scalar(scalar_layout) => {
820-
self.visit_scalar(op, scalar_layout)?;
830+
let scalar = self.read_immediate_forced(op)?.to_scalar_or_uninit();
831+
self.visit_scalar(scalar, scalar_layout)?;
832+
}
833+
Abi::ScalarPair(a_layout, b_layout) => {
834+
// We would validate these things as we descend into the fields,
835+
// but that can miss bugs in layout computation. Layout computation
836+
// is subtle due to enums having ScalarPair layout, where one field
837+
// is the discriminant.
838+
if cfg!(debug_assertions) {
839+
let (a, b) = self.read_immediate_forced(op)?.to_scalar_or_uninit_pair();
840+
self.visit_scalar(a, a_layout)?;
841+
self.visit_scalar(b, b_layout)?;
842+
}
821843
}
822-
Abi::ScalarPair { .. } | Abi::Vector { .. } => {
823-
// These have fields that we already visited above, so we already checked
824-
// all their scalar-level restrictions.
825-
// There is also no equivalent to `rustc_layout_scalar_valid_range_start`
826-
// that would make skipping them here an issue.
844+
Abi::Vector { .. } => {
845+
// No checks here, we assume layout computation gets this right.
846+
// (This is harder to check since Miri does not represent these as `Immediate`.)
827847
}
828848
Abi::Aggregate { .. } => {
829849
// Nothing to do.

compiler/rustc_mir_transform/src/const_prop.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
415415

416416
// Try to read the local as an immediate so that if it is representable as a scalar, we can
417417
// handle it as such, but otherwise, just return the value as is.
418-
Some(match self.ecx.try_read_immediate(&op) {
418+
Some(match self.ecx.read_immediate_raw(&op, /*force*/ false) {
419419
Ok(Ok(imm)) => imm.into(),
420420
_ => op,
421421
})
@@ -709,8 +709,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
709709
return;
710710
}
711711

712-
// FIXME> figure out what to do when try_read_immediate fails
713-
let imm = self.use_ecx(|this| this.ecx.try_read_immediate(value));
712+
// FIXME> figure out what to do when read_immediate_raw fails
713+
let imm = self.use_ecx(|this| this.ecx.read_immediate_raw(value, /*force*/ false));
714714

715715
if let Some(Ok(imm)) = imm {
716716
match *imm {

compiler/rustc_mir_transform/src/const_prop_lint.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
412412

413413
// Try to read the local as an immediate so that if it is representable as a scalar, we can
414414
// handle it as such, but otherwise, just return the value as is.
415-
Some(match self.ecx.try_read_immediate(&op) {
415+
Some(match self.ecx.read_immediate_raw(&op, /*force*/ false) {
416416
Ok(Ok(imm)) => imm.into(),
417417
_ => op,
418418
})

compiler/rustc_resolve/src/late.rs

+5
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,9 @@ struct DiagnosticMetadata<'ast> {
486486
current_where_predicate: Option<&'ast WherePredicate>,
487487

488488
current_type_path: Option<&'ast Ty>,
489+
490+
/// The current impl items (used to suggest).
491+
current_impl_items: Option<&'ast [P<AssocItem>]>,
489492
}
490493

491494
struct LateResolutionVisitor<'a, 'b, 'ast> {
@@ -1637,7 +1640,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
16371640
items: ref impl_items,
16381641
..
16391642
}) => {
1643+
self.diagnostic_metadata.current_impl_items = Some(impl_items);
16401644
self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items);
1645+
self.diagnostic_metadata.current_impl_items = None;
16411646
}
16421647

16431648
ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => {

0 commit comments

Comments
 (0)