Auto merge of #122869 - matthiaskrgr:rollup-0navj4l, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #121619 (Experimental feature postfix match) - #122370 (Gracefully handle `AnonConst` in `diagnostic_hir_wf_check()`) - #122537 (interpret/allocation: fix aliasing issue in interpreter and refactor getters a bit) - #122542 (coverage: Clean up marker statements that aren't needed later) - #122800 (Add `NonNull::<[T]>::is_empty`.) - #122820 (Stop using `<DefId as Ord>` in various diagnostic situations) - #122847 (Suggest `RUST_MIN_STACK` workaround on overflow) - #122855 (Fix Itanium mangling usizes) - #122863 (add more ice tests ) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
1447f9d38c
73 changed files with 1199 additions and 247 deletions
|
@ -1437,7 +1437,7 @@ pub enum ExprKind {
|
|||
/// `'label: loop { block }`
|
||||
Loop(P<Block>, Option<Label>, Span),
|
||||
/// A `match` block.
|
||||
Match(P<Expr>, ThinVec<Arm>),
|
||||
Match(P<Expr>, ThinVec<Arm>, MatchKind),
|
||||
/// A closure (e.g., `move |a, b, c| a + b + c`).
|
||||
Closure(Box<Closure>),
|
||||
/// A block (`'label: { ... }`).
|
||||
|
@ -1762,6 +1762,15 @@ pub enum StrStyle {
|
|||
Raw(u8),
|
||||
}
|
||||
|
||||
/// The kind of match expression
|
||||
#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq)]
|
||||
pub enum MatchKind {
|
||||
/// match expr { ... }
|
||||
Prefix,
|
||||
/// expr.match { ... }
|
||||
Postfix,
|
||||
}
|
||||
|
||||
/// A literal in a meta item.
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct MetaItemLit {
|
||||
|
|
|
@ -1425,7 +1425,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
|||
visit_opt(label, |label| vis.visit_label(label));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
ExprKind::Match(expr, arms) => {
|
||||
ExprKind::Match(expr, arms, _kind) => {
|
||||
vis.visit_expr(expr);
|
||||
arms.flat_map_in_place(|arm| vis.flat_map_arm(arm));
|
||||
}
|
||||
|
|
|
@ -923,7 +923,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
|||
visit_opt!(visitor, visit_label, opt_label);
|
||||
try_visit!(visitor.visit_block(block));
|
||||
}
|
||||
ExprKind::Match(subexpression, arms) => {
|
||||
ExprKind::Match(subexpression, arms, _kind) => {
|
||||
try_visit!(visitor.visit_expr(subexpression));
|
||||
walk_list!(visitor, visit_arm, arms);
|
||||
}
|
||||
|
|
|
@ -181,10 +181,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)
|
||||
}),
|
||||
ExprKind::TryBlock(body) => self.lower_expr_try_block(body),
|
||||
ExprKind::Match(expr, arms) => hir::ExprKind::Match(
|
||||
ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match(
|
||||
self.lower_expr(expr),
|
||||
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
|
||||
hir::MatchSource::Normal,
|
||||
match kind {
|
||||
MatchKind::Prefix => hir::MatchSource::Normal,
|
||||
MatchKind::Postfix => hir::MatchSource::Postfix,
|
||||
},
|
||||
),
|
||||
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
|
||||
ExprKind::Closure(box Closure {
|
||||
|
|
|
@ -564,6 +564,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(generic_const_items, "generic const items are experimental");
|
||||
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
|
||||
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
|
||||
gate_all!(postfix_match, "postfix match is experimental");
|
||||
|
||||
if !visitor.features.never_patterns {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::pp::Breaks::Inconsistent;
|
||||
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
|
||||
use ast::ForLoopKind;
|
||||
use ast::{ForLoopKind, MatchKind};
|
||||
use itertools::{Itertools, Position};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
|
@ -589,12 +589,22 @@ impl<'a> State<'a> {
|
|||
self.word_nbsp("loop");
|
||||
self.print_block_with_attrs(blk, attrs);
|
||||
}
|
||||
ast::ExprKind::Match(expr, arms) => {
|
||||
ast::ExprKind::Match(expr, arms, match_kind) => {
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
self.word_nbsp("match");
|
||||
self.print_expr_as_cond(expr);
|
||||
self.space();
|
||||
|
||||
match match_kind {
|
||||
MatchKind::Prefix => {
|
||||
self.word_nbsp("match");
|
||||
self.print_expr_as_cond(expr);
|
||||
self.space();
|
||||
}
|
||||
MatchKind::Postfix => {
|
||||
self.print_expr_as_cond(expr);
|
||||
self.word_nbsp(".match");
|
||||
}
|
||||
}
|
||||
|
||||
self.bopen();
|
||||
self.print_inner_attributes_no_trailing_hardbreak(attrs);
|
||||
for arm in arms {
|
||||
|
|
|
@ -245,7 +245,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
ExprKind::Let(_, local_expr, _, _) => {
|
||||
self.manage_cond_expr(local_expr);
|
||||
}
|
||||
ExprKind::Match(local_expr, _) => {
|
||||
ExprKind::Match(local_expr, ..) => {
|
||||
self.manage_cond_expr(local_expr);
|
||||
}
|
||||
ExprKind::MethodCall(call) => {
|
||||
|
|
|
@ -132,7 +132,7 @@ fn cs_partial_cmp(
|
|||
// Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354
|
||||
|
||||
if !tag_then_data
|
||||
&& let ExprKind::Match(_, arms) = &mut expr1.kind
|
||||
&& let ExprKind::Match(_, arms, _) = &mut expr1.kind
|
||||
&& let Some(last) = arms.last_mut()
|
||||
&& let PatKind::Wild = last.pat.kind
|
||||
{
|
||||
|
|
|
@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
|
|||
use crate::deriving::generic::*;
|
||||
use crate::deriving::path_std;
|
||||
|
||||
use ast::EnumDef;
|
||||
use rustc_ast::{self as ast, MetaItem};
|
||||
use rustc_ast::{self as ast, EnumDef, MetaItem};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
|
|
@ -85,14 +85,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
|
||||
let bx = self;
|
||||
|
||||
match coverage.kind {
|
||||
// Marker statements have no effect during codegen,
|
||||
// so return early and don't create `func_coverage`.
|
||||
CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => return,
|
||||
// Match exhaustively to ensure that newly-added kinds are classified correctly.
|
||||
CoverageKind::CounterIncrement { .. } | CoverageKind::ExpressionUsed { .. } => {}
|
||||
}
|
||||
|
||||
let Some(function_coverage_info) =
|
||||
bx.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
|
||||
else {
|
||||
|
@ -109,7 +101,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
let Coverage { kind } = coverage;
|
||||
match *kind {
|
||||
CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
|
||||
"unexpected marker statement {kind:?} should have caused an early return"
|
||||
"marker statement {kind:?} should have been removed by CleanupPostBorrowck"
|
||||
),
|
||||
CoverageKind::CounterIncrement { id } => {
|
||||
func_coverage.mark_counter_id_seen(id);
|
||||
|
|
|
@ -1159,11 +1159,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
};
|
||||
|
||||
// Side-step AllocRef and directly access the underlying bytes more efficiently.
|
||||
// (We are staying inside the bounds here so all is good.)
|
||||
// (We are staying inside the bounds here and all bytes do get overwritten so all is good.)
|
||||
let alloc_id = alloc_ref.alloc_id;
|
||||
let bytes = alloc_ref
|
||||
.alloc
|
||||
.get_bytes_mut(&alloc_ref.tcx, alloc_ref.range)
|
||||
.get_bytes_unchecked_for_overwrite(&alloc_ref.tcx, alloc_ref.range)
|
||||
.map_err(move |e| e.to_interp_error(alloc_id))?;
|
||||
// `zip` would stop when the first iterator ends; we want to definitely
|
||||
// cover all of `bytes`.
|
||||
|
@ -1184,6 +1184,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
self.mem_copy_repeatedly(src, dest, size, 1, nonoverlapping)
|
||||
}
|
||||
|
||||
/// Performs `num_copies` many copies of `size` many bytes from `src` to `dest + i*size` (where
|
||||
/// `i` is the index of the copy).
|
||||
///
|
||||
/// Either `nonoverlapping` must be true or `num_copies` must be 1; doing repeated copies that
|
||||
/// may overlap is not supported.
|
||||
pub fn mem_copy_repeatedly(
|
||||
&mut self,
|
||||
src: Pointer<Option<M::Provenance>>,
|
||||
|
@ -1245,8 +1250,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
(dest_alloc_id, dest_prov),
|
||||
dest_range,
|
||||
)?;
|
||||
// Yes we do overwrite all bytes in `dest_bytes`.
|
||||
let dest_bytes = dest_alloc
|
||||
.get_bytes_mut_ptr(&tcx, dest_range)
|
||||
.get_bytes_unchecked_for_overwrite_ptr(&tcx, dest_range)
|
||||
.map_err(|e| e.to_interp_error(dest_alloc_id))?
|
||||
.as_mut_ptr();
|
||||
|
||||
|
@ -1280,6 +1286,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
}
|
||||
if num_copies > 1 {
|
||||
assert!(nonoverlapping, "multi-copy only supported in non-overlapping mode");
|
||||
}
|
||||
|
||||
let size_in_bytes = size.bytes_usize();
|
||||
// For particularly large arrays (where this is perf-sensitive) it's common that
|
||||
|
@ -1292,6 +1301,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
} else if src_alloc_id == dest_alloc_id {
|
||||
let mut dest_ptr = dest_bytes;
|
||||
for _ in 0..num_copies {
|
||||
// Here we rely on `src` and `dest` being non-overlapping if there is more than
|
||||
// one copy.
|
||||
ptr::copy(src_bytes, dest_ptr, size_in_bytes);
|
||||
dest_ptr = dest_ptr.add(size_in_bytes);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
|||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_infer::traits::Reveal;
|
||||
use rustc_middle::mir::coverage::CoverageKind;
|
||||
use rustc_middle::mir::interpret::Scalar;
|
||||
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
|
@ -345,11 +346,21 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
self.fail(location, format!("explicit `{kind:?}` is forbidden"));
|
||||
}
|
||||
}
|
||||
StatementKind::Coverage(coverage) => {
|
||||
let kind = &coverage.kind;
|
||||
if self.mir_phase >= MirPhase::Analysis(AnalysisPhase::PostCleanup)
|
||||
&& let CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. } = kind
|
||||
{
|
||||
self.fail(
|
||||
location,
|
||||
format!("{kind:?} should have been removed after analysis"),
|
||||
);
|
||||
}
|
||||
}
|
||||
StatementKind::Assign(..)
|
||||
| StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Intrinsic(_)
|
||||
| StatementKind::Coverage(_)
|
||||
| StatementKind::ConstEvalCounter
|
||||
| StatementKind::PlaceMention(..)
|
||||
| StatementKind::Nop => {}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Signal handler for rustc
|
||||
//! Primarily used to extract a backtrace from stack overflow
|
||||
|
||||
use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE};
|
||||
use std::alloc::{alloc, Layout};
|
||||
use std::{fmt, mem, ptr};
|
||||
|
||||
|
@ -100,7 +101,10 @@ extern "C" fn print_stack_trace(_: libc::c_int) {
|
|||
written += 1;
|
||||
}
|
||||
raw_errln!("note: we would appreciate a report at https://github.com/rust-lang/rust");
|
||||
written += 1;
|
||||
// get the current stack size WITHOUT blocking and double it
|
||||
let new_size = STACK_SIZE.get().copied().unwrap_or(DEFAULT_STACK_SIZE) * 2;
|
||||
raw_errln!("help: you can increase rustc's stack size by setting RUST_MIN_STACK={new_size}");
|
||||
written += 2;
|
||||
if written > 24 {
|
||||
// We probably just scrolled the earlier "we got SIGSEGV" message off the terminal
|
||||
raw_errln!("note: backtrace dumped due to SIGSEGV! resuming signal");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::base::ExtCtxt;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, PatKind, UnOp};
|
||||
use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp};
|
||||
use rustc_ast::{attr, token, util::literal};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
|
@ -524,7 +524,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
}
|
||||
|
||||
pub fn expr_match(&self, span: Span, arg: P<ast::Expr>, arms: ThinVec<ast::Arm>) -> P<Expr> {
|
||||
self.expr(span, ast::ExprKind::Match(arg, arms))
|
||||
self.expr(span, ast::ExprKind::Match(arg, arms, MatchKind::Prefix))
|
||||
}
|
||||
|
||||
pub fn expr_if(
|
||||
|
|
|
@ -559,6 +559,8 @@ declare_features! (
|
|||
(unstable, offset_of_nested, "1.77.0", Some(120140)),
|
||||
/// Allows using `#[optimize(X)]`.
|
||||
(unstable, optimize_attribute, "1.34.0", Some(54882)),
|
||||
/// Allows postfix match `expr.match { ... }`
|
||||
(unstable, postfix_match, "CURRENT_RUSTC_VERSION", Some(121618)),
|
||||
/// Allows macro attributes on expressions, statements and non-inline modules.
|
||||
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
|
||||
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
|
||||
|
|
|
@ -2015,6 +2015,8 @@ pub enum LocalSource {
|
|||
pub enum MatchSource {
|
||||
/// A `match _ { .. }`.
|
||||
Normal,
|
||||
/// A `expr.match { .. }`.
|
||||
Postfix,
|
||||
/// A desugared `for _ in _ { .. }` loop.
|
||||
ForLoopDesugar,
|
||||
/// A desugared `?` operator.
|
||||
|
@ -2031,6 +2033,7 @@ impl MatchSource {
|
|||
use MatchSource::*;
|
||||
match self {
|
||||
Normal => "match",
|
||||
Postfix => ".match",
|
||||
ForLoopDesugar => "for",
|
||||
TryDesugar(_) => "?",
|
||||
AwaitDesugar => ".await",
|
||||
|
|
|
@ -163,6 +163,16 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
kind: hir::GenericParamKind::Type { default: Some(ty), .. },
|
||||
..
|
||||
}) => vec![*ty],
|
||||
hir::Node::AnonConst(_)
|
||||
if let Some(const_param_id) =
|
||||
tcx.hir().opt_const_param_default_param_def_id(hir_id)
|
||||
&& let hir::Node::GenericParam(hir::GenericParam {
|
||||
kind: hir::GenericParamKind::Const { ty, .. },
|
||||
..
|
||||
}) = tcx.hir_node_by_def_id(const_param_id) =>
|
||||
{
|
||||
vec![*ty]
|
||||
}
|
||||
ref node => bug!("Unexpected node {:?}", node),
|
||||
},
|
||||
WellFormedLoc::Param { function: _, param_idx } => {
|
||||
|
|
|
@ -48,12 +48,20 @@ pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dy
|
|||
}
|
||||
}
|
||||
|
||||
const STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||
pub static STACK_SIZE: OnceLock<usize> = OnceLock::new();
|
||||
pub const DEFAULT_STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||
|
||||
fn get_stack_size() -> Option<usize> {
|
||||
// FIXME: Hacks on hacks. If the env is trying to override the stack size
|
||||
// then *don't* set it explicitly.
|
||||
env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE)
|
||||
fn init_stack_size() -> usize {
|
||||
// Obey the environment setting or default
|
||||
*STACK_SIZE.get_or_init(|| {
|
||||
env::var_os("RUST_MIN_STACK")
|
||||
.map(|os_str| os_str.to_string_lossy().into_owned())
|
||||
// ignore if it is set to nothing
|
||||
.filter(|s| s.trim() != "")
|
||||
.map(|s| s.trim().parse::<usize>().unwrap())
|
||||
// otherwise pick a consistent default
|
||||
.unwrap_or(DEFAULT_STACK_SIZE)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn run_in_thread_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||
|
@ -66,10 +74,7 @@ pub(crate) fn run_in_thread_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
|||
// the parallel compiler, in particular to ensure there is no accidental
|
||||
// sharing of data between the main thread and the compilation thread
|
||||
// (which might cause problems for the parallel compiler).
|
||||
let mut builder = thread::Builder::new().name("rustc".to_string());
|
||||
if let Some(size) = get_stack_size() {
|
||||
builder = builder.stack_size(size);
|
||||
}
|
||||
let builder = thread::Builder::new().name("rustc".to_string()).stack_size(init_stack_size());
|
||||
|
||||
// We build the session globals and run `f` on the spawned thread, because
|
||||
// `SessionGlobals` does not impl `Send` in the non-parallel compiler.
|
||||
|
@ -120,7 +125,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
|||
});
|
||||
}
|
||||
|
||||
let mut builder = rayon::ThreadPoolBuilder::new()
|
||||
let builder = rayon::ThreadPoolBuilder::new()
|
||||
.thread_name(|_| "rustc".to_string())
|
||||
.acquire_thread_handler(jobserver::acquire_thread)
|
||||
.release_thread_handler(jobserver::release_thread)
|
||||
|
@ -144,10 +149,8 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
|||
on_panic.disable();
|
||||
})
|
||||
.unwrap();
|
||||
});
|
||||
if let Some(size) = get_stack_size() {
|
||||
builder = builder.stack_size(size);
|
||||
}
|
||||
})
|
||||
.stack_size(init_stack_size());
|
||||
|
||||
// We create the session globals on the main thread, then create the thread
|
||||
// pool. Upon creation, each worker thread created gets a copy of the
|
||||
|
|
|
@ -865,7 +865,7 @@ trait UnusedDelimLint {
|
|||
(iter, UnusedDelimsCtx::ForIterExpr, true, None, Some(body.span.lo()), true)
|
||||
}
|
||||
|
||||
Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
|
||||
Match(ref head, ..) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
|
||||
let left = e.span.lo() + rustc_span::BytePos(5);
|
||||
(head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None, true)
|
||||
}
|
||||
|
@ -1133,7 +1133,7 @@ impl EarlyLintPass for UnusedParens {
|
|||
}
|
||||
return;
|
||||
}
|
||||
ExprKind::Match(ref _expr, ref arm) => {
|
||||
ExprKind::Match(ref _expr, ref arm, _) => {
|
||||
for a in arm {
|
||||
if let Some(body) = &a.body {
|
||||
self.check_unused_delims_expr(
|
||||
|
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "2.4.1"
|
||||
derivative = "2.2.0"
|
||||
either = "1.5.0"
|
||||
field-offset = "0.3.5"
|
||||
gsgdt = "0.1.2"
|
||||
|
|
|
@ -456,7 +456,7 @@ impl<'tcx> Const<'tcx> {
|
|||
}
|
||||
|
||||
/// An unevaluated (potentially generic) constant used in MIR.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable)]
|
||||
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct UnevaluatedConst<'tcx> {
|
||||
pub def: DefId,
|
||||
|
|
|
@ -88,14 +88,13 @@ pub enum CoverageKind {
|
|||
/// Marks a span that might otherwise not be represented in MIR, so that
|
||||
/// coverage instrumentation can associate it with its enclosing block/BCB.
|
||||
///
|
||||
/// Only used by the `InstrumentCoverage` pass, and has no effect during
|
||||
/// codegen.
|
||||
/// Should be erased before codegen (at some point after `InstrumentCoverage`).
|
||||
SpanMarker,
|
||||
|
||||
/// Marks its enclosing basic block with an ID that can be referred to by
|
||||
/// side data in [`BranchInfo`].
|
||||
///
|
||||
/// Has no effect during codegen.
|
||||
/// Should be erased before codegen (at some point after `InstrumentCoverage`).
|
||||
BlockMarker { id: BlockMarkerId },
|
||||
|
||||
/// Marks the point in MIR control flow represented by a coverage counter.
|
||||
|
|
|
@ -37,9 +37,16 @@ pub trait AllocBytes:
|
|||
/// Create a zeroed `AllocBytes` of the specified size and alignment.
|
||||
/// Returns `None` if we ran out of memory on the host.
|
||||
fn zeroed(size: Size, _align: Align) -> Option<Self>;
|
||||
|
||||
/// Gives direct access to the raw underlying storage.
|
||||
///
|
||||
/// Crucially this pointer is compatible with:
|
||||
/// - other pointers retunred by this method, and
|
||||
/// - references returned from `deref()`, as long as there was no write.
|
||||
fn as_mut_ptr(&mut self) -> *mut u8;
|
||||
}
|
||||
|
||||
// Default `bytes` for `Allocation` is a `Box<[u8]>`.
|
||||
/// Default `bytes` for `Allocation` is a `Box<u8>`.
|
||||
impl AllocBytes for Box<[u8]> {
|
||||
fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, _align: Align) -> Self {
|
||||
Box::<[u8]>::from(slice.into())
|
||||
|
@ -51,6 +58,11 @@ impl AllocBytes for Box<[u8]> {
|
|||
let bytes = unsafe { bytes.assume_init() };
|
||||
Some(bytes)
|
||||
}
|
||||
|
||||
fn as_mut_ptr(&mut self) -> *mut u8 {
|
||||
// Carefully avoiding any intermediate references.
|
||||
ptr::addr_of_mut!(**self).cast()
|
||||
}
|
||||
}
|
||||
|
||||
/// This type represents an Allocation in the Miri/CTFE core engine.
|
||||
|
@ -399,10 +411,6 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
|
|||
|
||||
/// Byte accessors.
|
||||
impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
|
||||
pub fn base_addr(&self) -> *const u8 {
|
||||
self.bytes.as_ptr()
|
||||
}
|
||||
|
||||
/// This is the entirely abstraction-violating way to just grab the raw bytes without
|
||||
/// caring about provenance or initialization.
|
||||
///
|
||||
|
@ -452,13 +460,14 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
|
|||
Ok(self.get_bytes_unchecked(range))
|
||||
}
|
||||
|
||||
/// Just calling this already marks everything as defined and removes provenance,
|
||||
/// so be sure to actually put data there!
|
||||
/// This is the entirely abstraction-violating way to just get mutable access to the raw bytes.
|
||||
/// Just calling this already marks everything as defined and removes provenance, so be sure to
|
||||
/// actually overwrite all the data there!
|
||||
///
|
||||
/// It is the caller's responsibility to check bounds and alignment beforehand.
|
||||
/// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
|
||||
/// on `InterpCx` instead.
|
||||
pub fn get_bytes_mut(
|
||||
pub fn get_bytes_unchecked_for_overwrite(
|
||||
&mut self,
|
||||
cx: &impl HasDataLayout,
|
||||
range: AllocRange,
|
||||
|
@ -469,8 +478,9 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
|
|||
Ok(&mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()])
|
||||
}
|
||||
|
||||
/// A raw pointer variant of `get_bytes_mut` that avoids invalidating existing aliases into this memory.
|
||||
pub fn get_bytes_mut_ptr(
|
||||
/// A raw pointer variant of `get_bytes_unchecked_for_overwrite` that avoids invalidating existing immutable aliases
|
||||
/// into this memory.
|
||||
pub fn get_bytes_unchecked_for_overwrite_ptr(
|
||||
&mut self,
|
||||
cx: &impl HasDataLayout,
|
||||
range: AllocRange,
|
||||
|
@ -479,10 +489,19 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
|
|||
self.provenance.clear(range, cx)?;
|
||||
|
||||
assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check
|
||||
// Cruciall, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`.
|
||||
let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize());
|
||||
let len = range.end().bytes_usize() - range.start.bytes_usize();
|
||||
Ok(ptr::slice_from_raw_parts_mut(begin_ptr, len))
|
||||
}
|
||||
|
||||
/// This gives direct mutable access to the entire buffer, just exposing their internal state
|
||||
/// without reseting anything. Directly exposes `AllocBytes::as_mut_ptr`. Only works if
|
||||
/// `OFFSET_IS_ADDR` is true.
|
||||
pub fn get_bytes_unchecked_raw_mut(&mut self) -> *mut u8 {
|
||||
assert!(Prov::OFFSET_IS_ADDR);
|
||||
self.bytes.as_mut_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
/// Reading and writing.
|
||||
|
@ -589,7 +608,8 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
|
|||
};
|
||||
|
||||
let endian = cx.data_layout().endian;
|
||||
let dst = self.get_bytes_mut(cx, range)?;
|
||||
// Yes we do overwrite all the bytes in `dst`.
|
||||
let dst = self.get_bytes_unchecked_for_overwrite(cx, range)?;
|
||||
write_target_uint(endian, dst, bytes).unwrap();
|
||||
|
||||
// See if we have to also store some provenance.
|
||||
|
|
|
@ -284,8 +284,15 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
|
|||
/// order of the category, thereby influencing diagnostic output.
|
||||
///
|
||||
/// See also `rustc_const_eval::borrow_check::constraints`.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(
|
||||
PartialOrd,
|
||||
Ord,
|
||||
PartialOrd = "feature_allow_slow_enum",
|
||||
Ord = "feature_allow_slow_enum"
|
||||
)]
|
||||
pub enum ConstraintCategory<'tcx> {
|
||||
Return(ReturnConstraint),
|
||||
Yield,
|
||||
|
@ -295,6 +302,7 @@ pub enum ConstraintCategory<'tcx> {
|
|||
Cast {
|
||||
/// Whether this is an unsizing cast and if yes, this contains the target type.
|
||||
/// Region variables are erased to ReErased.
|
||||
#[derivative(PartialOrd = "ignore", Ord = "ignore")]
|
||||
unsize_to: Option<Ty<'tcx>>,
|
||||
},
|
||||
|
||||
|
@ -304,7 +312,7 @@ pub enum ConstraintCategory<'tcx> {
|
|||
ClosureBounds,
|
||||
|
||||
/// Contains the function type if available.
|
||||
CallArgument(Option<Ty<'tcx>>),
|
||||
CallArgument(#[derivative(PartialOrd = "ignore", Ord = "ignore")] Option<Ty<'tcx>>),
|
||||
CopyBound,
|
||||
SizedBound,
|
||||
Assignment,
|
||||
|
|
|
@ -124,6 +124,7 @@ pub enum AnalysisPhase {
|
|||
/// * [`TerminatorKind::FalseEdge`]
|
||||
/// * [`StatementKind::FakeRead`]
|
||||
/// * [`StatementKind::AscribeUserType`]
|
||||
/// * [`StatementKind::Coverage`] with [`CoverageKind::BlockMarker`] or [`CoverageKind::SpanMarker`]
|
||||
/// * [`Rvalue::Ref`] with `BorrowKind::Fake`
|
||||
///
|
||||
/// Furthermore, `Deref` projections must be the first projection within any place (if they
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::error::UnsupportedFnAbi;
|
|||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use crate::query::TyCtxtAt;
|
||||
use crate::ty::normalize_erasing_regions::NormalizationError;
|
||||
use crate::ty::{self, ConstKind, Ty, TyCtxt, TypeVisitableExt};
|
||||
use crate::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_error_messages::DiagMessage;
|
||||
use rustc_errors::{
|
||||
Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
|
||||
|
@ -356,21 +356,10 @@ impl<'tcx> SizeSkeleton<'tcx> {
|
|||
.ok_or_else(|| &*tcx.arena.alloc(LayoutError::SizeOverflow(ty)))?;
|
||||
return Ok(SizeSkeleton::Known(Size::from_bytes(size)));
|
||||
}
|
||||
let len = tcx.expand_abstract_consts(len);
|
||||
let prev = ty::Const::from_target_usize(tcx, s.bytes());
|
||||
let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, prev) else {
|
||||
return Err(tcx.arena.alloc(LayoutError::SizeOverflow(ty)));
|
||||
};
|
||||
Ok(SizeSkeleton::Generic(gen_size))
|
||||
Err(tcx.arena.alloc(LayoutError::Unknown(ty)))
|
||||
}
|
||||
SizeSkeleton::Pointer { .. } => Err(err),
|
||||
SizeSkeleton::Generic(g) => {
|
||||
let len = tcx.expand_abstract_consts(len);
|
||||
let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, g) else {
|
||||
return Err(tcx.arena.alloc(LayoutError::SizeOverflow(ty)));
|
||||
};
|
||||
Ok(SizeSkeleton::Generic(gen_size))
|
||||
}
|
||||
SizeSkeleton::Generic(_) => Err(tcx.arena.alloc(LayoutError::Unknown(ty))),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -468,56 +457,6 @@ impl<'tcx> SizeSkeleton<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// When creating the layout for types with abstract consts in their size (i.e. [usize; 4 * N]),
|
||||
/// to ensure that they have a canonical order and can be compared directly we combine all
|
||||
/// constants, and sort the other terms. This allows comparison of expressions of sizes,
|
||||
/// allowing for things like transmuting between types that depend on generic consts.
|
||||
/// This returns `None` if multiplication of constants overflows.
|
||||
fn mul_sorted_consts<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
a: ty::Const<'tcx>,
|
||||
b: ty::Const<'tcx>,
|
||||
) -> Option<ty::Const<'tcx>> {
|
||||
use crate::mir::BinOp::Mul;
|
||||
|
||||
let mut work = vec![a, b];
|
||||
let mut done = vec![];
|
||||
while let Some(n) = work.pop() {
|
||||
if let ConstKind::Expr(ty::Expr::Binop(Mul, l, r)) = n.kind() {
|
||||
work.push(l);
|
||||
work.push(r)
|
||||
} else {
|
||||
done.push(n);
|
||||
}
|
||||
}
|
||||
let mut k = 1;
|
||||
let mut overflow = false;
|
||||
done.retain(|c| {
|
||||
let Some(c) = c.try_eval_target_usize(tcx, param_env) else {
|
||||
return true;
|
||||
};
|
||||
let Some(next) = c.checked_mul(k) else {
|
||||
overflow = true;
|
||||
return false;
|
||||
};
|
||||
k = next;
|
||||
false
|
||||
});
|
||||
if overflow {
|
||||
return None;
|
||||
}
|
||||
if k != 1 {
|
||||
done.push(ty::Const::from_target_usize(tcx, k));
|
||||
} else if k == 0 {
|
||||
return Some(ty::Const::from_target_usize(tcx, 0));
|
||||
}
|
||||
done.sort_unstable();
|
||||
|
||||
// create a single tree from the buffer
|
||||
done.into_iter().reduce(|acc, n| ty::Const::new_expr(tcx, ty::Expr::Binop(Mul, n, acc), n.ty()))
|
||||
}
|
||||
|
||||
pub trait HasTyCtxt<'tcx>: HasDataLayout {
|
||||
fn tcx(&self) -> TyCtxt<'tcx>;
|
||||
}
|
||||
|
|
|
@ -481,6 +481,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
|||
// when the iterator is an uninhabited type. unreachable_code will trigger instead.
|
||||
hir::MatchSource::ForLoopDesugar if arms.len() == 1 => {}
|
||||
hir::MatchSource::ForLoopDesugar
|
||||
| hir::MatchSource::Postfix
|
||||
| hir::MatchSource::Normal
|
||||
| hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report),
|
||||
// Unreachable patterns in try and await expressions occur when one of
|
||||
|
|
|
@ -5,15 +5,20 @@
|
|||
//! - [`AscribeUserType`]
|
||||
//! - [`FakeRead`]
|
||||
//! - [`Assign`] statements with a [`Fake`] borrow
|
||||
//! - [`Coverage`] statements of kind [`BlockMarker`] or [`SpanMarker`]
|
||||
//!
|
||||
//! [`AscribeUserType`]: rustc_middle::mir::StatementKind::AscribeUserType
|
||||
//! [`Assign`]: rustc_middle::mir::StatementKind::Assign
|
||||
//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
|
||||
//! [`Nop`]: rustc_middle::mir::StatementKind::Nop
|
||||
//! [`Fake`]: rustc_middle::mir::BorrowKind::Fake
|
||||
//! [`Coverage`]: rustc_middle::mir::StatementKind::Coverage
|
||||
//! [`BlockMarker`]: rustc_middle::mir::coverage::CoverageKind::BlockMarker
|
||||
//! [`SpanMarker`]: rustc_middle::mir::coverage::CoverageKind::SpanMarker
|
||||
|
||||
use crate::MirPass;
|
||||
use rustc_middle::mir::{Body, BorrowKind, Rvalue, StatementKind, TerminatorKind};
|
||||
use rustc_middle::mir::coverage::CoverageKind;
|
||||
use rustc_middle::mir::{Body, BorrowKind, Coverage, Rvalue, StatementKind, TerminatorKind};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
pub struct CleanupPostBorrowck;
|
||||
|
@ -25,6 +30,12 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
|
|||
match statement.kind {
|
||||
StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake, _)))
|
||||
| StatementKind::Coverage(box Coverage {
|
||||
// These kinds of coverage statements are markers inserted during
|
||||
// MIR building, and are not needed after InstrumentCoverage.
|
||||
kind: CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. },
|
||||
..
|
||||
})
|
||||
| StatementKind::FakeRead(..) => statement.make_nop(),
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::errors;
|
|||
use crate::maybe_recover_from_interpolated_ty_qpath;
|
||||
use ast::mut_visit::{noop_visit_expr, MutVisitor};
|
||||
use ast::token::IdentIsRaw;
|
||||
use ast::{CoroutineKind, ForLoopKind, GenBlockKind, Pat, Path, PathSegment};
|
||||
use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment};
|
||||
use core::mem;
|
||||
use core::ops::ControlFlow;
|
||||
use rustc_ast::ptr::P;
|
||||
|
@ -1379,6 +1379,13 @@ impl<'a> Parser<'a> {
|
|||
return Ok(self.mk_await_expr(self_arg, lo));
|
||||
}
|
||||
|
||||
// Post-fix match
|
||||
if self.eat_keyword(kw::Match) {
|
||||
let match_span = self.prev_token.span;
|
||||
self.psess.gated_spans.gate(sym::postfix_match, match_span);
|
||||
return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
|
||||
}
|
||||
|
||||
let fn_span_lo = self.token.span;
|
||||
let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
|
||||
self.check_trailing_angle_brackets(&seg, &[&token::OpenDelim(Delimiter::Parenthesis)]);
|
||||
|
@ -2894,8 +2901,20 @@ impl<'a> Parser<'a> {
|
|||
/// Parses a `match ... { ... }` expression (`match` token already eaten).
|
||||
fn parse_expr_match(&mut self) -> PResult<'a, P<Expr>> {
|
||||
let match_span = self.prev_token.span;
|
||||
let lo = self.prev_token.span;
|
||||
let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
||||
|
||||
self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix)
|
||||
}
|
||||
|
||||
/// Parses the block of a `match expr { ... }` or a `expr.match { ... }`
|
||||
/// expression. This is after the match token and scrutinee are eaten
|
||||
fn parse_match_block(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
match_span: Span,
|
||||
scrutinee: P<Expr>,
|
||||
match_kind: MatchKind,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
if let Err(mut e) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
|
||||
if self.token == token::Semi {
|
||||
e.span_suggestion_short(
|
||||
|
@ -2938,7 +2957,7 @@ impl<'a> Parser<'a> {
|
|||
});
|
||||
return Ok(self.mk_expr_with_attrs(
|
||||
span,
|
||||
ExprKind::Match(scrutinee, arms),
|
||||
ExprKind::Match(scrutinee, arms, match_kind),
|
||||
attrs,
|
||||
));
|
||||
}
|
||||
|
@ -2946,7 +2965,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
let hi = self.token.span;
|
||||
self.bump();
|
||||
Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms), attrs))
|
||||
Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms, match_kind), attrs))
|
||||
}
|
||||
|
||||
/// Attempt to recover from match arm body with statements and no surrounding braces.
|
||||
|
@ -3955,7 +3974,7 @@ impl MutVisitor for CondChecker<'_> {
|
|||
| ExprKind::While(_, _, _)
|
||||
| ExprKind::ForLoop { .. }
|
||||
| ExprKind::Loop(_, _, _)
|
||||
| ExprKind::Match(_, _)
|
||||
| ExprKind::Match(_, _, _)
|
||||
| ExprKind::Closure(_)
|
||||
| ExprKind::Block(_, _)
|
||||
| ExprKind::Gen(_, _, _)
|
||||
|
|
|
@ -48,7 +48,7 @@ impl NonConstExpr {
|
|||
Self::Match(TryDesugar(_)) => &[sym::const_try],
|
||||
|
||||
// All other expressions are allowed.
|
||||
Self::Loop(Loop | While) | Self::Match(Normal | FormatArgs) => &[],
|
||||
Self::Loop(Loop | While) | Self::Match(Normal | Postfix | FormatArgs) => &[],
|
||||
};
|
||||
|
||||
Some(gates)
|
||||
|
|
|
@ -1335,6 +1335,7 @@ symbols! {
|
|||
poll,
|
||||
poll_next,
|
||||
post_dash_lto: "post-lto",
|
||||
postfix_match,
|
||||
powerpc_target_feature,
|
||||
powf128,
|
||||
powf16,
|
||||
|
|
|
@ -525,8 +525,8 @@ fn encode_ty<'tcx>(
|
|||
"{}",
|
||||
&len.try_to_scalar()
|
||||
.unwrap()
|
||||
.to_u64()
|
||||
.unwrap_or_else(|_| panic!("failed to convert length to u64"))
|
||||
.to_target_usize(&tcx.data_layout)
|
||||
.expect("Array lens are defined in usize")
|
||||
);
|
||||
s.push_str(&encode_ty(tcx, *ty0, dict, options));
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue