Skip to content

Commit 362211d

Browse files
committed
Auto merge of rust-lang#154326 - JonathanBrouwer:rollup-MflIdQW, r=JonathanBrouwer
Rollup of 5 pull requests Successful merges: - rust-lang#152710 (Unalign `PackedFingerprint` on all hosts, not just x86 and x86-64) - rust-lang#153874 (constify const Fn*: Destruct) - rust-lang#154097 (improve validation error messages: show surrounding type) - rust-lang#154277 (use `minicore` more in testing inline assembly) - rust-lang#154293 (Use verbose span suggestion for type const)
2 parents 63154b7 + 9396ab2 commit 362211d

167 files changed

Lines changed: 843 additions & 623 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/const_eval/eval_queries.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ fn const_validate_mplace<'tcx>(
425425
cid: GlobalId<'tcx>,
426426
) -> Result<(), ErrorHandled> {
427427
let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
428-
let mut ref_tracking = RefTracking::new(mplace.clone());
428+
let mut ref_tracking = RefTracking::new(mplace.clone(), mplace.layout.ty);
429429
let mut inner = false;
430430
while let Some((mplace, path)) = ref_tracking.next() {
431431
let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) {

compiler/rustc_const_eval/src/interpret/validity.rs

Lines changed: 55 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ use super::UnsupportedOpInfo::*;
4747
macro_rules! err_validation_failure {
4848
($where:expr, $msg:expr ) => {{
4949
let where_ = &$where;
50-
let path = if !where_.is_empty() {
50+
let path = if !where_.projs.is_empty() {
5151
let mut path = String::new();
52-
write_path(&mut path, where_);
52+
write_path(&mut path, &where_.projs);
5353
Some(path)
5454
} else {
5555
None
@@ -59,6 +59,7 @@ macro_rules! err_validation_failure {
5959
use ValidationErrorKind::*;
6060
let msg = ValidationErrorKind::from($msg);
6161
err_ub!(ValidationError {
62+
orig_ty: where_.orig_ty,
6263
path,
6364
ptr_bytes_warning: msg.ptr_bytes_warning(),
6465
msg: msg.to_string(),
@@ -234,7 +235,7 @@ fn fmt_range(r: WrappingRange, max_hi: u128) -> String {
234235
/// So we track a `Vec<PathElem>` where `PathElem` contains all the data we
235236
/// need to later print something for the user.
236237
#[derive(Copy, Clone, Debug)]
237-
pub enum PathElem {
238+
pub enum PathElem<'tcx> {
238239
Field(Symbol),
239240
Variant(Symbol),
240241
CoroutineState(VariantIdx),
@@ -244,10 +245,22 @@ pub enum PathElem {
244245
Deref,
245246
EnumTag,
246247
CoroutineTag,
247-
DynDowncast,
248+
DynDowncast(Ty<'tcx>),
248249
Vtable,
249250
}
250251

252+
#[derive(Clone, Debug)]
253+
pub struct Path<'tcx> {
254+
orig_ty: Ty<'tcx>,
255+
projs: Vec<PathElem<'tcx>>,
256+
}
257+
258+
impl<'tcx> Path<'tcx> {
259+
fn new(ty: Ty<'tcx>) -> Self {
260+
Self { orig_ty: ty, projs: vec![] }
261+
}
262+
}
263+
251264
/// Extra things to check for during validation of CTFE results.
252265
#[derive(Copy, Clone)]
253266
pub enum CtfeValidationMode {
@@ -280,16 +293,10 @@ pub struct RefTracking<T, PATH = ()> {
280293
todo: Vec<(T, PATH)>,
281294
}
282295

283-
impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH> {
296+
impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH> RefTracking<T, PATH> {
284297
pub fn empty() -> Self {
285298
RefTracking { seen: FxHashSet::default(), todo: vec![] }
286299
}
287-
pub fn new(val: T) -> Self {
288-
let mut ref_tracking_for_consts =
289-
RefTracking { seen: FxHashSet::default(), todo: vec![(val.clone(), PATH::default())] };
290-
ref_tracking_for_consts.seen.insert(val);
291-
ref_tracking_for_consts
292-
}
293300
pub fn next(&mut self) -> Option<(T, PATH)> {
294301
self.todo.pop()
295302
}
@@ -304,8 +311,17 @@ impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH>
304311
}
305312
}
306313

314+
impl<'tcx, T: Clone + Eq + Hash + std::fmt::Debug> RefTracking<T, Path<'tcx>> {
315+
pub fn new(val: T, ty: Ty<'tcx>) -> Self {
316+
let mut ref_tracking_for_consts =
317+
RefTracking { seen: FxHashSet::default(), todo: vec![(val.clone(), Path::new(ty))] };
318+
ref_tracking_for_consts.seen.insert(val);
319+
ref_tracking_for_consts
320+
}
321+
}
322+
307323
/// Format a path
308-
fn write_path(out: &mut String, path: &[PathElem]) {
324+
fn write_path(out: &mut String, path: &[PathElem<'_>]) {
309325
use self::PathElem::*;
310326

311327
for elem in path.iter() {
@@ -323,7 +339,7 @@ fn write_path(out: &mut String, path: &[PathElem]) {
323339
// even use the usual syntax because we are just showing the projections,
324340
// not the root.
325341
Deref => write!(out, ".<deref>"),
326-
DynDowncast => write!(out, ".<dyn-downcast>"),
342+
DynDowncast(ty) => write!(out, ".<dyn-downcast({ty})>"),
327343
Vtable => write!(out, ".<vtable>"),
328344
}
329345
.unwrap()
@@ -382,10 +398,9 @@ impl RangeSet {
382398

383399
struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> {
384400
/// The `path` may be pushed to, but the part that is present when a function
385-
/// starts must not be changed! `visit_fields` and `visit_array` rely on
386-
/// this stack discipline.
387-
path: Vec<PathElem>,
388-
ref_tracking: Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>>,
401+
/// starts must not be changed! `with_elem` relies on this stack discipline.
402+
path: Path<'tcx>,
403+
ref_tracking: Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Path<'tcx>>>,
389404
/// `None` indicates this is not validating for CTFE (but for runtime).
390405
ctfe_mode: Option<CtfeValidationMode>,
391406
ecx: &'rt mut InterpCx<'tcx, M>,
@@ -404,7 +419,12 @@ struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> {
404419
}
405420

406421
impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
407-
fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem {
422+
fn aggregate_field_path_elem(
423+
&mut self,
424+
layout: TyAndLayout<'tcx>,
425+
field: usize,
426+
field_ty: Ty<'tcx>,
427+
) -> PathElem<'tcx> {
408428
// First, check if we are projecting to a variant.
409429
match layout.variants {
410430
Variants::Multiple { tag_field, .. } => {
@@ -474,7 +494,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
474494
// dyn traits
475495
ty::Dynamic(..) => {
476496
assert_eq!(field, 0);
477-
PathElem::DynDowncast
497+
PathElem::DynDowncast(field_ty)
478498
}
479499

480500
// nothing else has an aggregate layout
@@ -484,17 +504,17 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
484504

485505
fn with_elem<R>(
486506
&mut self,
487-
elem: PathElem,
507+
elem: PathElem<'tcx>,
488508
f: impl FnOnce(&mut Self) -> InterpResult<'tcx, R>,
489509
) -> InterpResult<'tcx, R> {
490510
// Remember the old state
491-
let path_len = self.path.len();
511+
let path_len = self.path.projs.len();
492512
// Record new element
493-
self.path.push(elem);
513+
self.path.projs.push(elem);
494514
// Perform operation
495515
let r = f(self)?;
496516
// Undo changes
497-
self.path.truncate(path_len);
517+
self.path.projs.truncate(path_len);
498518
// Done
499519
interp_ok(r)
500520
}
@@ -796,10 +816,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
796816
ref_tracking.track(place, || {
797817
// We need to clone the path anyway, make sure it gets created
798818
// with enough space for the additional `Deref`.
799-
let mut new_path = Vec::with_capacity(path.len() + 1);
800-
new_path.extend(path);
801-
new_path.push(PathElem::Deref);
802-
new_path
819+
let mut new_projs = Vec::with_capacity(path.projs.len() + 1);
820+
new_projs.extend(&path.projs);
821+
new_projs.push(PathElem::Deref);
822+
Path { projs: new_projs, orig_ty: path.orig_ty }
803823
});
804824
}
805825
interp_ok(())
@@ -1220,7 +1240,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
12201240
field: usize,
12211241
new_val: &PlaceTy<'tcx, M::Provenance>,
12221242
) -> InterpResult<'tcx> {
1223-
let elem = self.aggregate_field_path_elem(old_val.layout, field);
1243+
let elem = self.aggregate_field_path_elem(old_val.layout, field, new_val.layout.ty);
12241244
self.with_elem(elem, move |this| this.visit_value(new_val))
12251245
}
12261246

@@ -1385,7 +1405,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
13851405
access.bad.start.bytes() / layout.size.bytes(),
13861406
)
13871407
.unwrap();
1388-
self.path.push(PathElem::ArrayElem(i));
1408+
self.path.projs.push(PathElem::ArrayElem(i));
13891409

13901410
if matches!(kind, Ub(InvalidUninitBytes(_))) {
13911411
err_validation_failure!(self.path, Uninit { expected })
@@ -1515,8 +1535,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
15151535
fn validate_operand_internal(
15161536
&mut self,
15171537
val: &PlaceTy<'tcx, M::Provenance>,
1518-
path: Vec<PathElem>,
1519-
ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>>,
1538+
path: Path<'tcx>,
1539+
ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Path<'tcx>>>,
15201540
ctfe_mode: Option<CtfeValidationMode>,
15211541
reset_provenance_and_padding: bool,
15221542
) -> InterpResult<'tcx> {
@@ -1569,8 +1589,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
15691589
pub(crate) fn const_validate_operand(
15701590
&mut self,
15711591
val: &PlaceTy<'tcx, M::Provenance>,
1572-
path: Vec<PathElem>,
1573-
ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>,
1592+
path: Path<'tcx>,
1593+
ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Path<'tcx>>,
15741594
ctfe_mode: CtfeValidationMode,
15751595
) -> InterpResult<'tcx> {
15761596
self.validate_operand_internal(
@@ -1599,14 +1619,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
15991619
reset_provenance_and_padding,
16001620
?val,
16011621
);
1602-
16031622
// Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's
16041623
// still correct to not use `ctfe_mode`: that mode is for validation of the final constant
16051624
// value, it rules out things like `UnsafeCell` in awkward places.
16061625
if !recursive {
16071626
return self.validate_operand_internal(
16081627
val,
1609-
vec![],
1628+
Path::new(val.layout.ty),
16101629
None,
16111630
None,
16121631
reset_provenance_and_padding,
@@ -1616,7 +1635,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
16161635
let mut ref_tracking = RefTracking::empty();
16171636
self.validate_operand_internal(
16181637
val,
1619-
vec![],
1638+
Path::new(val.layout.ty),
16201639
Some(&mut ref_tracking),
16211640
None,
16221641
reset_provenance_and_padding,

compiler/rustc_data_structures/src/fingerprint.rs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -181,22 +181,24 @@ impl<D: Decoder> Decodable<D> for Fingerprint {
181181
}
182182
}
183183

184-
// `PackedFingerprint` wraps a `Fingerprint`. Its purpose is to, on certain
185-
// architectures, behave like a `Fingerprint` without alignment requirements.
186-
// This behavior is only enabled on x86 and x86_64, where the impact of
187-
// unaligned accesses is tolerable in small doses.
188-
//
189-
// This may be preferable to use in large collections of structs containing
190-
// fingerprints, as it can reduce memory consumption by preventing the padding
191-
// that the more strictly-aligned `Fingerprint` can introduce. An application of
192-
// this is in the query dependency graph, which contains a large collection of
193-
// `DepNode`s. As of this writing, the size of a `DepNode` decreases by ~30%
194-
// (from 24 bytes to 17) by using the packed representation here, which
195-
// noticeably decreases total memory usage when compiling large crates.
196-
//
197-
// The wrapped `Fingerprint` is private to reduce the chance of a client
198-
// invoking undefined behavior by taking a reference to the packed field.
199-
#[cfg_attr(any(target_arch = "x86", target_arch = "x86_64"), repr(packed))]
184+
/// `PackedFingerprint` wraps a `Fingerprint`.
185+
/// Its purpose is to behave like a `Fingerprint` without alignment requirements.
186+
///
187+
/// This may be preferable to use in large collections of structs containing
188+
/// fingerprints, as it can reduce memory consumption by preventing the padding
189+
/// that the more strictly-aligned `Fingerprint` can introduce. An application of
190+
/// this is in the query dependency graph, which contains a large collection of
191+
/// `DepNode`s. As of this writing, the size of a `DepNode` decreases by 25%
192+
/// (from 24 bytes to 18) by using the packed representation here, which
193+
/// noticeably decreases total memory usage when compiling large crates.
194+
///
195+
/// (Unalignment was previously restricted to `x86` and `x86_64` hosts, but is
196+
/// now enabled by default for all host architectures, in the hope that the
197+
/// memory and cache savings should outweigh any unaligned access penalty.)
198+
///
199+
/// The wrapped `Fingerprint` is private to reduce the chance of a client
200+
/// invoking undefined behavior by taking a reference to the packed field.
201+
#[repr(packed)]
200202
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy, Hash)]
201203
pub struct PackedFingerprint(Fingerprint);
202204

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2947,7 +2947,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
29472947
);
29482948
if def_id.is_local() {
29492949
let name = tcx.def_path_str(def_id);
2950-
err.span_suggestion(
2950+
err.span_suggestion_verbose(
29512951
tcx.def_span(def_id).shrink_to_lo(),
29522952
format!("add `type` before `const` for `{name}`"),
29532953
format!("type "),

compiler/rustc_middle/src/dep_graph/dep_node.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,6 @@ mod size_asserts {
412412
use super::*;
413413
// tidy-alphabetical-start
414414
static_assert_size!(DepKind, 2);
415-
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
416415
static_assert_size!(DepNode, 18);
417-
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
418-
static_assert_size!(DepNode, 24);
419416
// tidy-alphabetical-end
420417
}

compiler/rustc_middle/src/mir/interpret/error.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,12 @@ pub enum UndefinedBehaviorInfo<'tcx> {
318318
/// Free-form case. Only for errors that are never caught! Used by miri
319319
Ub(String),
320320
/// Validation error.
321-
ValidationError { path: Option<String>, msg: String, ptr_bytes_warning: bool },
321+
ValidationError {
322+
orig_ty: Ty<'tcx>,
323+
path: Option<String>,
324+
msg: String,
325+
ptr_bytes_warning: bool,
326+
},
322327

323328
/// Unreachable code was executed.
324329
Unreachable,
@@ -457,11 +462,11 @@ impl<'tcx> fmt::Display for UndefinedBehaviorInfo<'tcx> {
457462
match self {
458463
Ub(msg) => write!(f, "{msg}"),
459464

460-
ValidationError { path: None, msg, .. } => {
461-
write!(f, "constructing invalid value: {msg}")
465+
ValidationError { orig_ty, path: None, msg, .. } => {
466+
write!(f, "constructing invalid value of type {orig_ty}: {msg}")
462467
}
463-
ValidationError { path: Some(path), msg, .. } => {
464-
write!(f, "constructing invalid value at {path}: {msg}")
468+
ValidationError { orig_ty, path: Some(path), msg, .. } => {
469+
write!(f, "constructing invalid value of type {orig_ty}: at {path}, {msg}")
465470
}
466471

467472
Unreachable => write!(f, "entering unreachable code"),

compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -797,12 +797,16 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
797797
| ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_))
798798
| ty::Error(_) => Ok(vec![]),
799799

800-
// Coroutines and closures could implement `[const] Drop`,
800+
// Closures are [const] Destruct when all of their upvars (captures) are [const] Destruct.
801+
ty::Closure(_, args) => {
802+
let closure_args = args.as_closure();
803+
Ok(vec![ty::TraitRef::new(cx, destruct_def_id, [closure_args.tupled_upvars_ty()])])
804+
}
805+
// Coroutines could implement `[const] Drop`,
801806
// but they don't really need to right now.
802-
ty::Closure(_, _)
803-
| ty::CoroutineClosure(_, _)
804-
| ty::Coroutine(_, _)
805-
| ty::CoroutineWitness(_, _) => Err(NoSolution),
807+
ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(_, _) => {
808+
Err(NoSolution)
809+
}
806810

807811
// FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop`
808812
// if their inner type implements it.

compiler/rustc_trait_selection/src/traits/effects.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -472,12 +472,17 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>(
472472
| ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_))
473473
| ty::Error(_) => thin_vec![],
474474

475-
// Coroutines and closures could implement `[const] Drop`,
475+
// Closures are [const] Destruct when all of their upvars (captures) are [const] Destruct.
476+
ty::Closure(_, args) => {
477+
let closure_args = args.as_closure();
478+
thin_vec![ty::TraitRef::new(tcx, destruct_def_id, [closure_args.tupled_upvars_ty()])]
479+
}
480+
481+
// Coroutines could implement `[const] Drop`,
476482
// but they don't really need to right now.
477-
ty::Closure(_, _)
478-
| ty::CoroutineClosure(_, _)
479-
| ty::Coroutine(_, _)
480-
| ty::CoroutineWitness(_, _) => return Err(EvaluationFailure::NoSolution),
483+
ty::CoroutineClosure(_, _) | ty::Coroutine(_, _) | ty::CoroutineWitness(_, _) => {
484+
return Err(EvaluationFailure::NoSolution);
485+
}
481486

482487
// FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop`
483488
// if their inner type implements it.

0 commit comments

Comments
 (0)