summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:39 +0000
commit1376c5a617be5c25655d0d7cb63e3beaa5a6e026 (patch)
tree3bb8d61aee02bc7a15eab3f36e3b921afc2075d0 /compiler/rustc_mir_build
parentReleasing progress-linux version 1.69.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.tar.xz
rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.zip
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_build')
-rw-r--r--compiler/rustc_mir_build/messages.ftl (renamed from compiler/rustc_mir_build/locales/en-US.ftl)20
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/cfg.rs11
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs56
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs10
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs174
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs25
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs28
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs34
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/misc.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs45
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs68
-rw-r--r--compiler/rustc_mir_build/src/errors.rs51
-rw-r--r--compiler/rustc_mir_build/src/lib.rs3
-rw-r--r--compiler/rustc_mir_build/src/lints.rs11
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/block.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs21
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs727
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs54
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs53
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs57
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs36
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs2
29 files changed, 805 insertions, 728 deletions
diff --git a/compiler/rustc_mir_build/locales/en-US.ftl b/compiler/rustc_mir_build/messages.ftl
index 93e7fb330..f346cd483 100644
--- a/compiler/rustc_mir_build/locales/en-US.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -239,19 +239,9 @@ mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
} into the body
mir_build_bindings_with_variant_name =
- pattern binding `{$ident}` is named the same as one of the variants of the type `{$ty_path}`
+ pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}`
.suggestion = to match on the variant, qualify the path
-mir_build_irrefutable_let_patterns_generic_let = irrefutable `let` {$count ->
- [one] pattern
- *[other] patterns
- }
- .note = {$count ->
- [one] this pattern
- *[other] these patterns
- } will always match, so the `let` is useless
- .help = consider removing `let`
-
mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count ->
[one] pattern
*[other] patterns
@@ -331,6 +321,10 @@ mir_build_indirect_structural_match =
mir_build_nontrivial_structural_match =
to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+mir_build_type_not_structural_tip = the traits must be derived, manual `impl`s are not sufficient
+
+mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+
mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints
.range = ... with this range
.note = you likely meant to write mutually exclusive ranges
@@ -353,15 +347,13 @@ mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern",
mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-mir_build_res_defined_here = {$res} defined here
-
mir_build_adt_defined_here = `{$ty}` defined here
mir_build_variant_defined_here = not covered
mir_build_interpreted_as_const = introduce a variable instead
-mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as {$article} {$res} pattern, not a new variable
+mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable
mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count ->
[one] variant that isn't
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 2643d33ce..609ab1928 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -115,6 +115,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
initializer: Some(initializer),
lint_level,
else_block: Some(else_block),
+ span: _,
} => {
// When lowering the statement `let <pat> = <expr> else { <else> };`,
// the `<else>` block is nested in the parent scope enclosing this statement.
@@ -278,6 +279,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
initializer,
lint_level,
else_block: None,
+ span: _,
} => {
let ignores_expr_result = matches!(pattern.kind, PatKind::Wild);
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs
index d7b4b1f73..4f1623b4c 100644
--- a/compiler/rustc_mir_build/src/build/cfg.rs
+++ b/compiler/rustc_mir_build/src/build/cfg.rs
@@ -90,6 +90,17 @@ impl<'tcx> CFG<'tcx> {
self.push(block, stmt);
}
+ pub(crate) fn push_place_mention(
+ &mut self,
+ block: BasicBlock,
+ source_info: SourceInfo,
+ place: Place<'tcx>,
+ ) {
+ let kind = StatementKind::PlaceMention(Box::new(place));
+ let stmt = Statement { source_info, kind };
+ self.push(block, stmt);
+ }
+
pub(crate) fn terminate(
&mut self,
block: BasicBlock,
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index 33fdc1901..d385153ba 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -21,7 +21,7 @@ use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::{IndexSlice, IndexVec};
use rustc_middle::{
mir::*,
thir::*,
@@ -37,7 +37,7 @@ pub(super) fn build_custom_mir<'tcx>(
hir_id: HirId,
thir: &Thir<'tcx>,
expr: ExprId,
- params: &IndexVec<ParamId, Param<'tcx>>,
+ params: &IndexSlice<ParamId, Param<'tcx>>,
return_ty: Ty<'tcx>,
return_ty_span: Span,
span: Span,
@@ -49,7 +49,7 @@ pub(super) fn build_custom_mir<'tcx>(
phase: MirPhase::Built,
source_scopes: IndexVec::new(),
generator: None,
- local_decls: LocalDecls::new(),
+ local_decls: IndexVec::new(),
user_type_annotations: IndexVec::new(),
arg_count: params.len(),
spread_arg: None,
diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs
index d72770e70..12b2f5d80 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse.rs
@@ -1,4 +1,4 @@
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::IndexSlice;
use rustc_middle::{mir::*, thir::*, ty::Ty};
use rustc_span::Span;
@@ -81,7 +81,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
}
}
- pub fn parse_args(&mut self, params: &IndexVec<ParamId, Param<'tcx>>) -> PResult<()> {
+ pub fn parse_args(&mut self, params: &IndexSlice<ParamId, Param<'tcx>>) -> PResult<()> {
for param in params.iter() {
let (var, span) = {
let pat = param.pat.as_ref().unwrap();
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index dbba529ae..931fe1b24 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -1,8 +1,9 @@
use rustc_middle::mir::interpret::{ConstValue, Scalar};
use rustc_middle::mir::tcx::PlaceTy;
+use rustc_middle::ty::cast::mir_cast_kind;
use rustc_middle::{mir::*, thir::*, ty};
use rustc_span::Span;
-use rustc_target::abi::VariantIdx;
+use rustc_target::abi::{FieldIdx, VariantIdx};
use crate::build::custom::ParseError;
use crate::build::expr::as_constant::as_constant_inner;
@@ -55,15 +56,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
Ok(TerminatorKind::Drop {
place: self.parse_place(args[0])?,
target: self.parse_block(args[1])?,
- unwind: None,
- })
- },
- @call("mir_drop_and_replace", args) => {
- Ok(TerminatorKind::DropAndReplace {
- place: self.parse_place(args[0])?,
- value: self.parse_operand(args[1])?,
- target: self.parse_block(args[2])?,
- unwind: None,
+ unwind: UnwindAction::Continue,
})
},
@call("mir_call", args) => {
@@ -133,7 +126,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
args,
destination,
target: Some(target),
- cleanup: None,
+ unwind: UnwindAction::Continue,
from_hir_call: *from_hir_call,
fn_span: *fn_span,
})
@@ -142,8 +135,12 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
}
fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
- parse_by_kind!(self, expr_id, _, "rvalue",
+ parse_by_kind!(self, expr_id, expr, "rvalue",
@call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
+ @call("mir_cast_transmute", args) => {
+ let source = self.parse_operand(args[0])?;
+ Ok(Rvalue::Cast(CastKind::Transmute, source, expr.ty))
+ },
@call("mir_checked", args) => {
parse_by_kind!(self, args[0], _, "binary op",
ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp(
@@ -151,6 +148,11 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
)),
)
},
+ @call("mir_offset", args) => {
+ let ptr = self.parse_operand(args[0])?;
+ let offset = self.parse_operand(args[1])?;
+ Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
+ },
@call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
ExprKind::Borrow { borrow_kind, arg } => Ok(
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
@@ -167,6 +169,34 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
ExprKind::Repeat { value, count } => Ok(
Rvalue::Repeat(self.parse_operand(*value)?, *count)
),
+ ExprKind::Cast { source } => {
+ let source = self.parse_operand(*source)?;
+ let source_ty = source.ty(self.body.local_decls(), self.tcx);
+ let cast_kind = mir_cast_kind(source_ty, expr.ty);
+ Ok(Rvalue::Cast(cast_kind, source, expr.ty))
+ },
+ ExprKind::Tuple { fields } => Ok(
+ Rvalue::Aggregate(
+ Box::new(AggregateKind::Tuple),
+ fields.iter().map(|e| self.parse_operand(*e)).collect::<Result<_, _>>()?
+ )
+ ),
+ ExprKind::Array { fields } => {
+ let elem_ty = expr.ty.builtin_index().expect("ty must be an array");
+ Ok(Rvalue::Aggregate(
+ Box::new(AggregateKind::Array(elem_ty)),
+ fields.iter().map(|e| self.parse_operand(*e)).collect::<Result<_, _>>()?
+ ))
+ },
+ ExprKind::Adt(box AdtExpr{ adt_def, variant_index, substs, fields, .. }) => {
+ let is_union = adt_def.is_union();
+ let active_field_index = is_union.then(|| fields[0].name);
+
+ Ok(Rvalue::Aggregate(
+ Box::new(AggregateKind::Adt(adt_def.did(), *variant_index, substs, None, active_field_index)),
+ fields.iter().map(|f| self.parse_operand(f.expr)).collect::<Result<_, _>>()?
+ ))
+ },
_ => self.parse_operand(expr_id).map(Rvalue::Use),
)
}
@@ -198,7 +228,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
@call("mir_field", args) => {
let (parent, ty) = self.parse_place_inner(args[0])?;
- let field = Field::from_u32(self.parse_integer_literal(args[1])? as u32);
+ let field = FieldIdx::from_u32(self.parse_integer_literal(args[1])? as u32);
let field_ty = ty.field_ty(self.tcx, field);
let proj = PlaceElem::Field(field, field_ty);
let place = parent.project_deeper(&[proj], self.tcx);
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index cfacb5ea3..99291740a 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -62,21 +62,21 @@ pub fn as_constant_inner<'tcx>(
Constant { span, user_ty: None, literal }
}
ExprKind::NonHirLiteral { lit, ref user_ty } => {
- let user_ty = user_ty.as_ref().map(push_cuta).flatten();
+ let user_ty = user_ty.as_ref().and_then(push_cuta);
let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
Constant { span, user_ty, literal }
}
ExprKind::ZstLiteral { ref user_ty } => {
- let user_ty = user_ty.as_ref().map(push_cuta).flatten();
+ let user_ty = user_ty.as_ref().and_then(push_cuta);
let literal = ConstantKind::Val(ConstValue::ZeroSized, ty);
Constant { span, user_ty, literal }
}
ExprKind::NamedConst { def_id, substs, ref user_ty } => {
- let user_ty = user_ty.as_ref().map(push_cuta).flatten();
+ let user_ty = user_ty.as_ref().and_then(push_cuta);
let uneval = mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
let literal = ConstantKind::Unevaluated(uneval, ty);
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index ff3198847..6941da331 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -20,7 +20,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr: &Expr<'tcx>,
) -> BlockAnd<Operand<'tcx>> {
let local_scope = self.local_scope();
- self.as_operand(block, Some(local_scope), expr, None, NeedsTemporary::Maybe)
+ self.as_operand(block, Some(local_scope), expr, LocalInfo::Boring, NeedsTemporary::Maybe)
}
/// Returns an operand suitable for use until the end of the current scope expression and
@@ -102,7 +102,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
mut block: BasicBlock,
scope: Option<region::Scope>,
expr: &Expr<'tcx>,
- local_info: Option<Box<LocalInfo<'tcx>>>,
+ local_info: LocalInfo<'tcx>,
needs_temporary: NeedsTemporary,
) -> BlockAnd<Operand<'tcx>> {
let this = self;
@@ -124,8 +124,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
Category::Constant | Category::Place | Category::Rvalue(..) => {
let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
- if this.local_decls[operand].local_info.is_none() {
- this.local_decls[operand].local_info = local_info;
+ // Overwrite temp local info if we have something more interesting to record.
+ if !matches!(local_info, LocalInfo::Boring) {
+ let decl_info = this.local_decls[operand].local_info.as_mut().assert_crate_local();
+ if let LocalInfo::Boring | LocalInfo::BlockTailTemp(_) = **decl_info {
+ **decl_info = local_info;
+ }
}
block.and(Operand::Move(Place::from(operand)))
}
@@ -178,6 +182,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
- this.as_operand(block, scope, expr, None, NeedsTemporary::Maybe)
+ this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::Maybe)
}
}
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 33200b80a..fb775766c 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -13,9 +13,7 @@ use rustc_middle::thir::*;
use rustc_middle::ty::AdtDef;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, Variance};
use rustc_span::Span;
-use rustc_target::abi::VariantIdx;
-
-use rustc_index::vec::Idx;
+use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
use std::assert_matches::assert_matches;
use std::iter;
@@ -91,8 +89,8 @@ fn convert_to_hir_projections_and_truncate_for_capture(
let hir_projection = match mir_projection {
ProjectionElem::Deref => HirProjectionKind::Deref,
ProjectionElem::Field(field, _) => {
- let variant = variant.unwrap_or(VariantIdx::new(0));
- HirProjectionKind::Field(field.index() as u32, variant)
+ let variant = variant.unwrap_or(FIRST_VARIANT);
+ HirProjectionKind::Field(*field, variant)
}
ProjectionElem::Downcast(.., idx) => {
// We don't expect to see multi-variant enums here, as earlier
@@ -295,7 +293,7 @@ impl<'tcx> PlaceBuilder<'tcx> {
&self.projection
}
- pub(crate) fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
+ pub(crate) fn field(self, f: FieldIdx, ty: Ty<'tcx>) -> Self {
self.project(PlaceElem::Field(f, ty))
}
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index a4e48c154..8631749a5 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -1,14 +1,15 @@
//! See docs in `build/expr/mod.rs`.
-use rustc_index::vec::Idx;
+use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::ty::util::IntTypeExt;
-use rustc_target::abi::{Abi, Primitive};
+use rustc_target::abi::{Abi, FieldIdx, Primitive};
use crate::build::expr::as_place::PlaceBase;
use crate::build::expr::category::{Category, RvalueFunc};
use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
use rustc_hir::lang_items::LangItem;
use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::AssertKind;
use rustc_middle::mir::Place;
use rustc_middle::mir::*;
@@ -63,7 +64,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block,
scope,
&this.thir[value],
- None,
+ LocalInfo::Boring,
NeedsTemporary::No
)
);
@@ -72,19 +73,34 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
ExprKind::Binary { op, lhs, rhs } => {
let lhs = unpack!(
- block =
- this.as_operand(block, scope, &this.thir[lhs], None, NeedsTemporary::Maybe)
+ block = this.as_operand(
+ block,
+ scope,
+ &this.thir[lhs],
+ LocalInfo::Boring,
+ NeedsTemporary::Maybe
+ )
);
let rhs = unpack!(
- block =
- this.as_operand(block, scope, &this.thir[rhs], None, NeedsTemporary::No)
+ block = this.as_operand(
+ block,
+ scope,
+ &this.thir[rhs],
+ LocalInfo::Boring,
+ NeedsTemporary::No
+ )
);
this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
}
ExprKind::Unary { op, arg } => {
let arg = unpack!(
- block =
- this.as_operand(block, scope, &this.thir[arg], None, NeedsTemporary::No)
+ block = this.as_operand(
+ block,
+ scope,
+ &this.thir[arg],
+ LocalInfo::Boring,
+ NeedsTemporary::No
+ )
);
// Check for -MIN on signed integers
if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
@@ -155,7 +171,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
args: vec![Operand::Move(size), Operand::Move(align)],
destination: storage,
target: Some(success),
- cleanup: None,
+ unwind: UnwindAction::Continue,
from_hir_call: false,
fn_span: expr_span,
},
@@ -259,7 +275,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} else {
let ty = source.ty;
let source = unpack!(
- block = this.as_operand(block, scope, source, None, NeedsTemporary::No)
+ block = this.as_operand(block, scope, source, LocalInfo::Boring, NeedsTemporary::No)
);
(source, ty)
};
@@ -271,8 +287,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
ExprKind::Pointer { cast, source } => {
let source = unpack!(
- block =
- this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No)
+ block = this.as_operand(
+ block,
+ scope,
+ &this.thir[source],
+ LocalInfo::Boring,
+ NeedsTemporary::No
+ )
);
block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
}
@@ -305,7 +326,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// first process the set of fields
let el_ty = expr.ty.sequence_element_type(this.tcx);
- let fields: Vec<_> = fields
+ let fields: IndexVec<FieldIdx, _> = fields
.into_iter()
.copied()
.map(|f| {
@@ -314,7 +335,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block,
scope,
&this.thir[f],
- None,
+ LocalInfo::Boring,
NeedsTemporary::Maybe
)
)
@@ -326,7 +347,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ExprKind::Tuple { ref fields } => {
// see (*) above
// first process the set of fields
- let fields: Vec<_> = fields
+ let fields: IndexVec<FieldIdx, _> = fields
.into_iter()
.copied()
.map(|f| {
@@ -335,7 +356,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block,
scope,
&this.thir[f],
- None,
+ LocalInfo::Boring,
NeedsTemporary::Maybe
)
)
@@ -380,7 +401,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
// see (*) above
- let operands: Vec<_> = upvars
+ let operands: IndexVec<FieldIdx, _> = upvars
.into_iter()
.copied()
.map(|upvar| {
@@ -423,7 +444,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block,
scope,
upvar,
- None,
+ LocalInfo::Boring,
NeedsTemporary::Maybe
)
)
@@ -501,8 +522,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Category::of(&expr.kind),
Some(Category::Rvalue(RvalueFunc::AsRvalue) | Category::Constant)
));
- let operand =
- unpack!(block = this.as_operand(block, scope, expr, None, NeedsTemporary::No));
+ let operand = unpack!(
+ block =
+ this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No)
+ );
block.and(Rvalue::Use(operand))
}
}
@@ -519,30 +542,78 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
) -> BlockAnd<Rvalue<'tcx>> {
let source_info = self.source_info(span);
let bool_ty = self.tcx.types.bool;
- if self.check_overflow && op.is_checkable() && ty.is_integral() {
- let result_tup = self.tcx.mk_tup(&[ty, bool_ty]);
- let result_value = self.temp(result_tup, span);
-
- self.cfg.push_assign(
- block,
- source_info,
- result_value,
- Rvalue::CheckedBinaryOp(op, Box::new((lhs.to_copy(), rhs.to_copy()))),
- );
- let val_fld = Field::new(0);
- let of_fld = Field::new(1);
+ let rvalue = match op {
+ BinOp::Add | BinOp::Sub | BinOp::Mul if self.check_overflow && ty.is_integral() => {
+ let result_tup = self.tcx.mk_tup(&[ty, bool_ty]);
+ let result_value = self.temp(result_tup, span);
- let tcx = self.tcx;
- let val = tcx.mk_place_field(result_value, val_fld, ty);
- let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
+ self.cfg.push_assign(
+ block,
+ source_info,
+ result_value,
+ Rvalue::CheckedBinaryOp(op, Box::new((lhs.to_copy(), rhs.to_copy()))),
+ );
+ let val_fld = FieldIdx::new(0);
+ let of_fld = FieldIdx::new(1);
- let err = AssertKind::Overflow(op, lhs, rhs);
+ let tcx = self.tcx;
+ let val = tcx.mk_place_field(result_value, val_fld, ty);
+ let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
- block = self.assert(block, Operand::Move(of), false, err, span);
+ let err = AssertKind::Overflow(op, lhs, rhs);
+ block = self.assert(block, Operand::Move(of), false, err, span);
- block.and(Rvalue::Use(Operand::Move(val)))
- } else {
- if ty.is_integral() && (op == BinOp::Div || op == BinOp::Rem) {
+ Rvalue::Use(Operand::Move(val))
+ }
+ BinOp::Shl | BinOp::Shr if self.check_overflow && ty.is_integral() => {
+ // For an unsigned RHS, the shift is in-range for `rhs < bits`.
+ // For a signed RHS, `IntToInt` cast to the equivalent unsigned
+ // type and do that same comparison. Because the type is the
+ // same size, there's no negative shift amount that ends up
+ // overlapping with valid ones, thus it catches negatives too.
+ let (lhs_size, _) = ty.int_size_and_signed(self.tcx);
+ let rhs_ty = rhs.ty(&self.local_decls, self.tcx);
+ let (rhs_size, _) = rhs_ty.int_size_and_signed(self.tcx);
+
+ let (unsigned_rhs, unsigned_ty) = match rhs_ty.kind() {
+ ty::Uint(_) => (rhs.to_copy(), rhs_ty),
+ ty::Int(int_width) => {
+ let uint_ty = self.tcx.mk_mach_uint(int_width.to_unsigned());
+ let rhs_temp = self.temp(uint_ty, span);
+ self.cfg.push_assign(
+ block,
+ source_info,
+ rhs_temp,
+ Rvalue::Cast(CastKind::IntToInt, rhs.to_copy(), uint_ty),
+ );
+ (Operand::Move(rhs_temp), uint_ty)
+ }
+ _ => unreachable!("only integers are shiftable"),
+ };
+
+ // This can't overflow because the largest shiftable types are 128-bit,
+ // which fits in `u8`, the smallest possible `unsigned_ty`.
+ // (And `from_uint` will `bug!` if that's ever no longer true.)
+ let lhs_bits = Operand::const_from_scalar(
+ self.tcx,
+ unsigned_ty,
+ Scalar::from_uint(lhs_size.bits(), rhs_size),
+ span,
+ );
+
+ let inbounds = self.temp(bool_ty, span);
+ self.cfg.push_assign(
+ block,
+ source_info,
+ inbounds,
+ Rvalue::BinaryOp(BinOp::Lt, Box::new((unsigned_rhs, lhs_bits))),
+ );
+
+ let overflow_err = AssertKind::Overflow(op, lhs.to_copy(), rhs.to_copy());
+ block = self.assert(block, Operand::Move(inbounds), true, overflow_err, span);
+ Rvalue::BinaryOp(op, Box::new((lhs, rhs)))
+ }
+ BinOp::Div | BinOp::Rem if ty.is_integral() => {
// Checking division and remainder is more complex, since we 1. always check
// and 2. there are two possible failure cases, divide-by-zero and overflow.
@@ -601,10 +672,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block = self.assert(block, Operand::Move(of), false, overflow_err, span);
}
- }
- block.and(Rvalue::BinaryOp(op, Box::new((lhs, rhs))))
- }
+ Rvalue::BinaryOp(op, Box::new((lhs, rhs)))
+ }
+ _ => Rvalue::BinaryOp(op, Box::new((lhs, rhs))),
+ };
+ block.and(rvalue)
}
fn build_zero_repeat(
@@ -621,21 +694,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Repeating a const does nothing
} else {
// For a non-const, we may need to generate an appropriate `Drop`
- let value_operand =
- unpack!(block = this.as_operand(block, scope, value, None, NeedsTemporary::No));
+ let value_operand = unpack!(
+ block = this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No)
+ );
if let Operand::Move(to_drop) = value_operand {
let success = this.cfg.start_new_block();
this.cfg.terminate(
block,
outer_source_info,
- TerminatorKind::Drop { place: to_drop, target: success, unwind: None },
+ TerminatorKind::Drop {
+ place: to_drop,
+ target: success,
+ unwind: UnwindAction::Continue,
+ },
);
this.diverge_from(block);
block = success;
}
this.record_operands_moved(&[value_operand]);
}
- block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(elem_ty)), Vec::new()))
+ block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(elem_ty)), IndexVec::new()))
}
fn limit_capture_mutability(
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index 3d3cf7555..c8910c272 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -49,29 +49,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context);
- // Find out whether this temp is being created within the
- // tail expression of a block whose result is ignored.
- if let Some(tail_info) = this.block_context.currently_in_block_tail() {
- local_decl = local_decl.block_tail(tail_info);
- }
- match expr.kind {
+ let local_info = match expr.kind {
ExprKind::StaticRef { def_id, .. } => {
assert!(!this.tcx.is_thread_local_static(def_id));
local_decl.internal = true;
- local_decl.local_info =
- Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: false }));
+ LocalInfo::StaticRef { def_id, is_thread_local: false }
}
ExprKind::ThreadLocalRef(def_id) => {
assert!(this.tcx.is_thread_local_static(def_id));
local_decl.internal = true;
- local_decl.local_info =
- Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: true }));
+ LocalInfo::StaticRef { def_id, is_thread_local: true }
}
ExprKind::NamedConst { def_id, .. } | ExprKind::ConstParam { def_id, .. } => {
- local_decl.local_info = Some(Box::new(LocalInfo::ConstRef { def_id }));
+ LocalInfo::ConstRef { def_id }
}
- _ => {}
- }
+ // Find out whether this temp is being created within the
+ // tail expression of a block whose result is ignored.
+ _ if let Some(tail_info) = this.block_context.currently_in_block_tail() => {
+ LocalInfo::BlockTailTemp(tail_info)
+ }
+ _ => LocalInfo::Boring,
+ };
+ **local_decl.local_info.as_mut().assert_crate_local() = local_info;
this.local_decls.push(local_decl)
};
let temp_place = Place::from(temp);
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index dac9bf0a8..05a723a6b 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -6,7 +6,6 @@ use rustc_ast::InlineAsmOptions;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
-use rustc_index::vec::Idx;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
@@ -229,7 +228,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.cfg.terminate(
loop_block,
source_info,
- TerminatorKind::FalseUnwind { real_target: body_block, unwind: None },
+ TerminatorKind::FalseUnwind {
+ real_target: body_block,
+ unwind: UnwindAction::Continue,
+ },
);
this.diverge_from(loop_block);
@@ -265,7 +267,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TerminatorKind::Call {
func: fun,
args,
- cleanup: None,
+ unwind: UnwindAction::Continue,
destination,
// The presence or absence of a return edge affects control-flow sensitive
// MIR checks and ultimately whether code is accepted or not. We can only
@@ -319,7 +321,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// See the notes for `ExprKind::Array` in `as_rvalue` and for
// `ExprKind::Borrow` above.
let is_union = adt_def.is_union();
- let active_field_index = is_union.then(|| fields[0].name.index());
+ let active_field_index = is_union.then(|| fields[0].name);
let scope = this.local_scope();
@@ -328,7 +330,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let fields_map: FxHashMap<_, _> = fields
.into_iter()
.map(|f| {
- let local_info = Box::new(LocalInfo::AggregateTemp);
(
f.name,
unpack!(
@@ -336,7 +337,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block,
Some(scope),
&this.thir[f.expr],
- Some(local_info),
+ LocalInfo::AggregateTemp,
NeedsTemporary::Maybe,
)
),
@@ -344,10 +345,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
})
.collect();
- let field_names: Vec<_> =
- (0..adt_def.variant(variant_index).fields.len()).map(Field::new).collect();
+ let field_names = adt_def.variant(variant_index).fields.indices();
- let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
+ let fields = if let Some(FruInfo { base, field_types }) = base {
let place_builder =
unpack!(block = this.as_place_builder(block, &this.thir[*base]));
@@ -364,7 +364,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
})
.collect()
} else {
- field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect()
+ field_names.filter_map(|n| fields_map.get(&n).cloned()).collect()
};
let inferred_ty = expr.ty;
@@ -469,7 +469,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} else {
Some(destination_block)
},
- cleanup: None,
+ unwind: if options.contains(InlineAsmOptions::MAY_UNWIND) {
+ UnwindAction::Continue
+ } else {
+ UnwindAction::Unreachable
+ },
},
);
if options.contains(InlineAsmOptions::MAY_UNWIND) {
@@ -526,7 +530,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block,
Some(scope),
&this.thir[value],
- None,
+ LocalInfo::Boring,
NeedsTemporary::No
)
);
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index 780836851..ea5aeb67d 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -40,7 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Generate better code for things that don't need to be
// dropped.
if lhs.ty.needs_drop(this.tcx, this.param_env) {
- let rhs = unpack!(block = this.as_local_operand(block, rhs));
+ let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
let lhs = unpack!(block = this.as_place(block, lhs));
unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
} else {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index de2851a1a..4926ff85d 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -556,6 +556,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
_ => {
let place_builder = unpack!(block = self.as_place_builder(block, initializer));
+
+ if let Some(place) = place_builder.try_to_place(self) {
+ let source_info = self.source_info(initializer.span);
+ self.cfg.push_place_mention(block, source_info, place);
+ }
+
self.place_into_pattern(block, &irrefutable_pat, place_builder, true)
}
}
@@ -576,13 +582,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
false,
&mut [&mut candidate],
);
+
// For matches and function arguments, the place that is being matched
// can be set when creating the variables. But the place for
// let PATTERN = ... might not even exist until we do the assignment.
// so we set it here instead.
if set_match_place {
- let mut candidate_ref = &candidate;
- while let Some(next) = {
+ let mut next = Some(&candidate);
+ while let Some(candidate_ref) = next.take() {
for binding in &candidate_ref.bindings {
let local = self.var_local_id(binding.var_id, OutsideGuard);
// `try_to_place` may fail if it is unable to resolve the given
@@ -600,9 +607,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// };
// ```
if let Some(place) = initializer.try_to_place(self) {
- let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ let LocalInfo::User(BindingForm::Var(
VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
- )))) = self.local_decls[local].local_info else {
+ )) = **self.local_decls[local].local_info.as_mut().assert_crate_local() else {
bug!("Let binding to non-user variable.")
};
*match_place = Some(place);
@@ -610,9 +617,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
// All of the subcandidates should bind the same locals, so we
// only visit the first one.
- candidate_ref.subcandidates.get(0)
- } {
- candidate_ref = next;
+ next = candidate_ref.subcandidates.get(0)
}
}
@@ -1749,7 +1754,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span);
fake_borrow_temp.internal = self.local_decls[matched_place.local].internal;
- fake_borrow_temp.local_info = Some(Box::new(LocalInfo::FakeBorrow));
+ fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow));
let fake_borrow_temp = self.local_decls.push(fake_borrow_temp);
(matched_place, fake_borrow_temp)
@@ -1881,6 +1886,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// let place = Foo::new();
// match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) }
// => { let tmp2 = place; feed(tmp2) }, ... }
+ // ```
//
// And an input like:
//
@@ -2218,8 +2224,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) },
source_info,
internal: false,
- is_block_tail: None,
- local_info: Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::Var(
VarBindingForm {
binding_mode,
// hypothetically, `visit_primary_bindings` could try to unzip
@@ -2230,13 +2235,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
opt_match_place,
pat_span,
},
- ))))),
+ )))),
};
let for_arm_body = self.local_decls.push(local);
self.var_debug_info.push(VarDebugInfo {
name,
source_info: debug_source_info,
value: VarDebugInfoContents::Place(for_arm_body.into()),
+ argument_index: None,
});
let locals = if has_guard.0 {
let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> {
@@ -2247,15 +2253,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
user_ty: None,
source_info,
internal: false,
- is_block_tail: None,
- local_info: Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(
+ local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(
BindingForm::RefForGuard,
- )))),
+ ))),
});
self.var_debug_info.push(VarDebugInfo {
name,
source_info: debug_source_info,
value: VarDebugInfoContents::Place(ref_for_guard.into()),
+ argument_index: None,
});
LocalsForNode::ForGuard { ref_for_guard, for_arm_body }
} else {
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 2de89f67d..8a03ea7e2 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -263,7 +263,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
args: vec![Operand::Move(ref_string)],
destination: ref_str,
target: Some(eq_block),
- cleanup: None,
+ unwind: UnwindAction::Continue,
from_hir_call: false,
fn_span: source_info.span
}
@@ -466,7 +466,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
args: vec![val, expect],
destination: eq_result,
target: Some(eq_block),
- cleanup: None,
+ unwind: UnwindAction::Continue,
from_hir_call: false,
fn_span: source_info.span,
},
diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs
index baeb2718c..90d78658f 100644
--- a/compiler/rustc_mir_build/src/build/misc.rs
+++ b/compiler/rustc_mir_build/src/build/misc.rs
@@ -5,7 +5,7 @@ use crate::build::Builder;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -66,7 +66,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
pub(crate) fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> {
let tcx = self.tcx;
let ty = place.ty(&self.local_decls, tcx).ty;
- if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) {
+ if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty) {
Operand::Move(place)
} else {
Operand::Copy(place)
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index b3f9d8282..bc50bcbc3 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -3,6 +3,7 @@ use crate::build::expr::as_place::PlaceBuilder;
use crate::build::scope::DropKind;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
+use rustc_ast::attr;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sorted_map::SortedIndexMultiMap;
use rustc_errors::ErrorGuaranteed;
@@ -10,7 +11,7 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{GeneratorKind, Node};
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexSlice, IndexVec};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::middle::region;
@@ -24,6 +25,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_span::Symbol;
+use rustc_target::abi::FieldIdx;
use rustc_target::spec::abi::Abi;
use super::lints;
@@ -48,17 +50,15 @@ pub(crate) fn mir_built(
/// Construct the MIR for a given `DefId`.
fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
// Ensure unsafeck and abstract const building is ran before we steal the THIR.
- // We can't use `ensure()` for `thir_abstract_const` as it doesn't compute the query
- // if inputs are green. This can cause ICEs when calling `thir_abstract_const` after
- // THIR has been stolen if we haven't computed this query yet.
match def {
ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => {
- tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did));
- drop(tcx.thir_abstract_const_of_const_arg((did, const_param_did)));
+ tcx.ensure_with_value().thir_check_unsafety_for_const_arg((did, const_param_did));
+ tcx.ensure_with_value().thir_abstract_const_of_const_arg((did, const_param_did));
}
ty::WithOptConstParam { did, const_param_did: None } => {
- tcx.ensure().thir_check_unsafety(did);
- drop(tcx.thir_abstract_const(did));
+ tcx.ensure_with_value().thir_check_unsafety(did);
+ tcx.ensure_with_value().thir_abstract_const(did);
+ tcx.ensure_with_value().check_match(did);
}
}
@@ -683,7 +683,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Some functions always have overflow checks enabled,
// however, they may not get codegen'd, depending on
// the settings for the crate they are codegened in.
- let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks);
+ let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks);
// Respect -C overflow-checks.
check_overflow |= tcx.sess.overflow_checks();
// Constants always need overflow checks.
@@ -795,7 +795,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mutability = captured_place.mutability;
let mut projs = closure_env_projs.clone();
- projs.push(ProjectionElem::Field(Field::new(i), ty));
+ projs.push(ProjectionElem::Field(FieldIdx::new(i), ty));
match capture {
ty::UpvarCapture::ByValue => {}
ty::UpvarCapture::ByRef(..) => {
@@ -811,6 +811,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
name,
source_info: SourceInfo::outermost(captured_place.var_ident.span),
value: VarDebugInfoContents::Place(use_place),
+ argument_index: None,
});
let capture = Capture { captured_place, use_place, mutability };
@@ -822,12 +823,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn args_and_body(
&mut self,
mut block: BasicBlock,
- arguments: &IndexVec<ParamId, Param<'tcx>>,
+ arguments: &IndexSlice<ParamId, Param<'tcx>>,
argument_scope: region::Scope,
expr: &Expr<'tcx>,
) -> BlockAnd<()> {
// Allocate locals for the function arguments
- for param in arguments.iter() {
+ for (argument_index, param) in arguments.iter().enumerate() {
let source_info =
SourceInfo::outermost(param.pat.as_ref().map_or(self.fn_span, |pat| pat.span));
let arg_local =
@@ -839,6 +840,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
name,
source_info,
value: VarDebugInfoContents::Place(arg_local.into()),
+ argument_index: Some(argument_index as u16 + 1),
});
}
}
@@ -879,21 +881,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} => {
self.local_decls[local].mutability = mutability;
self.local_decls[local].source_info.scope = self.source_scope;
- self.local_decls[local].local_info = if let Some(kind) = param.self_kind {
- Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(
- BindingForm::ImplicitSelf(kind),
- ))))
- } else {
- let binding_mode = ty::BindingMode::BindByValue(mutability);
- Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
- VarBindingForm {
+ **self.local_decls[local].local_info.as_mut().assert_crate_local() =
+ if let Some(kind) = param.self_kind {
+ LocalInfo::User(BindingForm::ImplicitSelf(kind))
+ } else {
+ let binding_mode = ty::BindingMode::BindByValue(mutability);
+ LocalInfo::User(BindingForm::Var(VarBindingForm {
binding_mode,
opt_ty_info: param.ty_span,
opt_match_place: Some((None, span)),
pat_span: span,
- },
- )))))
- };
+ }))
+ };
self.var_indices.insert(var, LocalsForNode::One(local));
}
_ => {
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 591b41633..f32d2db4e 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -86,12 +86,12 @@ use std::mem;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::HirId;
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::{IndexSlice, IndexVec};
use rustc_middle::middle::region;
use rustc_middle::mir::*;
use rustc_middle::thir::{Expr, LintLevel};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{DesugaringKind, Span, DUMMY_SP};
#[derive(Debug)]
pub struct Scopes<'tcx> {
@@ -360,7 +360,7 @@ impl DropTree {
fn link_blocks<'tcx>(
&self,
cfg: &mut CFG<'tcx>,
- blocks: &IndexVec<DropIdx, Option<BasicBlock>>,
+ blocks: &IndexSlice<DropIdx, Option<BasicBlock>>,
) {
for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() {
let Some(block) = blocks[drop_idx] else { continue };
@@ -369,7 +369,7 @@ impl DropTree {
let terminator = TerminatorKind::Drop {
target: blocks[drop_data.1].unwrap(),
// The caller will handle this if needed.
- unwind: None,
+ unwind: UnwindAction::Terminate,
place: drop_data.0.local.into(),
};
cfg.terminate(block, drop_data.0.source_info, terminator);
@@ -1072,7 +1072,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TerminatorKind::Assert { .. }
| TerminatorKind::Call { .. }
| TerminatorKind::Drop { .. }
- | TerminatorKind::DropAndReplace { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::InlineAsm { .. }
),
@@ -1118,24 +1117,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
/// Utility function for *non*-scope code to build their own drops
+ /// Force a drop at this point in the MIR by creating a new block.
pub(crate) fn build_drop_and_replace(
&mut self,
block: BasicBlock,
span: Span,
place: Place<'tcx>,
- value: Operand<'tcx>,
+ value: Rvalue<'tcx>,
) -> BlockAnd<()> {
+ let span = self.tcx.with_stable_hashing_context(|hcx| {
+ span.mark_with_reason(None, DesugaringKind::Replace, self.tcx.sess.edition(), hcx)
+ });
let source_info = self.source_info(span);
- let next_target = self.cfg.start_new_block();
+
+ // create the new block for the assignment
+ let assign = self.cfg.start_new_block();
+ self.cfg.push_assign(assign, source_info, place, value.clone());
+
+ // create the new block for the assignment in the case of unwinding
+ let assign_unwind = self.cfg.start_new_cleanup_block();
+ self.cfg.push_assign(assign_unwind, source_info, place, value.clone());
self.cfg.terminate(
block,
source_info,
- TerminatorKind::DropAndReplace { place, value, target: next_target, unwind: None },
+ TerminatorKind::Drop {
+ place,
+ target: assign,
+ unwind: UnwindAction::Cleanup(assign_unwind),
+ },
);
self.diverge_from(block);
- next_target.unit()
+ assign.unit()
}
/// Creates an `Assert` terminator and return the success block.
@@ -1155,7 +1169,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.cfg.terminate(
block,
source_info,
- TerminatorKind::Assert { cond, expected, msg, target: success_block, cleanup: None },
+ TerminatorKind::Assert {
+ cond,
+ expected,
+ msg,
+ target: success_block,
+ unwind: UnwindAction::Continue,
+ },
);
self.diverge_from(block);
@@ -1234,7 +1254,11 @@ fn build_scope_drops<'tcx>(
cfg.terminate(
block,
source_info,
- TerminatorKind::Drop { place: local.into(), target: next, unwind: None },
+ TerminatorKind::Drop {
+ place: local.into(),
+ target: next,
+ unwind: UnwindAction::Continue,
+ },
);
block = next;
}
@@ -1413,18 +1437,24 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
fn add_entry(cfg: &mut CFG<'tcx>, from: BasicBlock, to: BasicBlock) {
let term = &mut cfg.block_data_mut(from).terminator_mut();
match &mut term.kind {
- TerminatorKind::Drop { unwind, .. }
- | TerminatorKind::DropAndReplace { unwind, .. }
- | TerminatorKind::FalseUnwind { unwind, .. }
- | TerminatorKind::Call { cleanup: unwind, .. }
- | TerminatorKind::Assert { cleanup: unwind, .. }
- | TerminatorKind::InlineAsm { cleanup: unwind, .. } => {
- *unwind = Some(to);
+ TerminatorKind::Drop { unwind, .. } => {
+ if let UnwindAction::Cleanup(unwind) = *unwind {
+ let source_info = term.source_info;
+ cfg.terminate(unwind, source_info, TerminatorKind::Goto { target: to });
+ } else {
+ *unwind = UnwindAction::Cleanup(to);
+ }
+ }
+ TerminatorKind::FalseUnwind { unwind, .. }
+ | TerminatorKind::Call { unwind, .. }
+ | TerminatorKind::Assert { unwind, .. }
+ | TerminatorKind::InlineAsm { unwind, .. } => {
+ *unwind = UnwindAction::Cleanup(to);
}
TerminatorKind::Goto { .. }
| TerminatorKind::SwitchInt { .. }
| TerminatorKind::Resume
- | TerminatorKind::Abort
+ | TerminatorKind::Terminate
| TerminatorKind::Return
| TerminatorKind::Unreachable
| TerminatorKind::Yield { .. }
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index dc4d2276e..43e787db4 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -6,11 +6,11 @@ use rustc_errors::{
error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
Handler, IntoDiagnostic, MultiSpan, SubdiagnosticMessage,
};
-use rustc_hir::def::Res;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::thir::Pat;
use rustc_middle::ty::{self, Ty};
-use rustc_span::{symbol::Ident, Span};
+use rustc_span::symbol::Symbol;
+use rustc_span::Span;
#[derive(LintDiagnostic)]
#[diag(mir_build_unconditional_recursion)]
@@ -534,18 +534,10 @@ pub struct TrailingIrrefutableLetPatterns {
#[derive(LintDiagnostic)]
#[diag(mir_build_bindings_with_variant_name, code = "E0170")]
pub struct BindingsWithVariantName {
- #[suggestion(code = "{ty_path}::{ident}", applicability = "machine-applicable")]
+ #[suggestion(code = "{ty_path}::{name}", applicability = "machine-applicable")]
pub suggestion: Option<Span>,
pub ty_path: String,
- pub ident: Ident,
-}
-
-#[derive(LintDiagnostic)]
-#[diag(mir_build_irrefutable_let_patterns_generic_let)]
-#[note]
-#[help]
-pub struct IrrefutableLetPatternsGenericLet {
- pub count: usize,
+ pub name: Symbol,
}
#[derive(LintDiagnostic)]
@@ -584,13 +576,12 @@ pub struct IrrefutableLetPatternsWhileLet {
#[diag(mir_build_borrow_of_moved_value)]
pub struct BorrowOfMovedValue<'tcx> {
#[primary_span]
- pub span: Span,
#[label]
#[label(mir_build_occurs_because_label)]
pub binding_span: Span,
#[label(mir_build_value_borrowed_label)]
pub conflicts_ref: Vec<Span>,
- pub name: Ident,
+ pub name: Symbol,
pub ty: Ty<'tcx>,
#[suggestion(code = "ref ", applicability = "machine-applicable")]
pub suggest_borrowing: Option<Span>,
@@ -602,7 +593,7 @@ pub struct MultipleMutBorrows {
#[primary_span]
pub span: Span,
#[subdiagnostic]
- pub occurences: Vec<Conflict>,
+ pub occurrences: Vec<Conflict>,
}
#[derive(Diagnostic)]
@@ -611,7 +602,7 @@ pub struct AlreadyBorrowed {
#[primary_span]
pub span: Span,
#[subdiagnostic]
- pub occurences: Vec<Conflict>,
+ pub occurrences: Vec<Conflict>,
}
#[derive(Diagnostic)]
@@ -620,7 +611,7 @@ pub struct AlreadyMutBorrowed {
#[primary_span]
pub span: Span,
#[subdiagnostic]
- pub occurences: Vec<Conflict>,
+ pub occurrences: Vec<Conflict>,
}
#[derive(Diagnostic)]
@@ -629,7 +620,7 @@ pub struct MovedWhileBorrowed {
#[primary_span]
pub span: Span,
#[subdiagnostic]
- pub occurences: Vec<Conflict>,
+ pub occurrences: Vec<Conflict>,
}
#[derive(Subdiagnostic)]
@@ -638,19 +629,19 @@ pub enum Conflict {
Mut {
#[primary_span]
span: Span,
- name: Ident,
+ name: Symbol,
},
#[label(mir_build_borrow)]
Ref {
#[primary_span]
span: Span,
- name: Ident,
+ name: Symbol,
},
#[label(mir_build_moved)]
Moved {
#[primary_span]
span: Span,
- name: Ident,
+ name: Symbol,
},
}
@@ -663,6 +654,8 @@ pub struct UnionPattern {
#[derive(Diagnostic)]
#[diag(mir_build_type_not_structural)]
+#[note(mir_build_type_not_structural_tip)]
+#[note(mir_build_type_not_structural_more_info)]
pub struct TypeNotStructural<'tcx> {
#[primary_span]
pub span: Span,
@@ -695,12 +688,16 @@ pub struct PointerPattern;
#[derive(LintDiagnostic)]
#[diag(mir_build_indirect_structural_match)]
+#[note(mir_build_type_not_structural_tip)]
+#[note(mir_build_type_not_structural_more_info)]
pub struct IndirectStructuralMatch<'tcx> {
pub non_sm_ty: Ty<'tcx>,
}
#[derive(LintDiagnostic)]
#[diag(mir_build_nontrivial_structural_match)]
+#[note(mir_build_type_not_structural_tip)]
+#[note(mir_build_type_not_structural_more_info)]
pub struct NontrivialStructuralMatch<'tcx> {
pub non_sm_ty: Ty<'tcx>,
}
@@ -796,8 +793,6 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
pub let_suggestion: Option<SuggestLet>,
#[subdiagnostic]
pub misc_suggestion: Option<MiscPatternSuggestion>,
- #[subdiagnostic]
- pub res_defined_here: Option<ResDefinedHere>,
}
#[derive(Subdiagnostic)]
@@ -832,14 +827,6 @@ impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> {
}
#[derive(Subdiagnostic)]
-#[label(mir_build_res_defined_here)]
-pub struct ResDefinedHere {
- #[primary_span]
- pub def_span: Span,
- pub res: Res,
-}
-
-#[derive(Subdiagnostic)]
#[suggestion(
mir_build_interpreted_as_const,
code = "{variable}_var",
@@ -849,9 +836,7 @@ pub struct ResDefinedHere {
pub struct InterpretedAsConst {
#[primary_span]
pub span: Span,
- pub article: &'static str,
pub variable: String,
- pub res: Res,
}
#[derive(Subdiagnostic)]
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index e10a264d3..3f9236c9d 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -8,7 +8,6 @@
#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(min_specialization)]
-#![feature(once_cell)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
@@ -28,7 +27,7 @@ use rustc_middle::ty::query::Providers;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_macros::fluent_messages;
-fluent_messages! { "../locales/en-US.ftl" }
+fluent_messages! { "../messages.ftl" }
pub fn provide(providers: &mut Providers) {
providers.check_match = thir::pattern::check_match;
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index f67f24b43..8e41957af 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -3,7 +3,7 @@ use rustc_data_structures::graph::iterate::{
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
};
use rustc_hir::def::DefKind;
-use rustc_middle::mir::{BasicBlock, BasicBlocks, Body, Operand, TerminatorKind};
+use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Operand, TerminatorKind};
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
use rustc_middle::ty::{self, Instance, TyCtxt};
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
@@ -18,7 +18,7 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let trait_substs = match tcx.trait_of_item(def_id.to_def_id()) {
Some(trait_def_id) => {
let trait_substs_count = tcx.generics_of(trait_def_id).count();
- &InternalSubsts::identity_for_item(tcx, def_id.to_def_id())[..trait_substs_count]
+ &InternalSubsts::identity_for_item(tcx, def_id)[..trait_substs_count]
}
_ => &[],
};
@@ -108,7 +108,7 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
match self.body[bb].terminator().kind {
// These terminators return control flow to the caller.
- TerminatorKind::Abort
+ TerminatorKind::Terminate
| TerminatorKind::GeneratorDrop
| TerminatorKind::Resume
| TerminatorKind::Return
@@ -128,7 +128,6 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
TerminatorKind::Assert { .. }
| TerminatorKind::Call { .. }
| TerminatorKind::Drop { .. }
- | TerminatorKind::DropAndReplace { .. }
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::Goto { .. }
@@ -150,7 +149,9 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
let terminator = self.body[bb].terminator();
- if terminator.unwind() == Some(&Some(target)) && terminator.successors().count() > 1 {
+ if terminator.unwind() == Some(&mir::UnwindAction::Cleanup(target))
+ && terminator.successors().count() > 1
+ {
return true;
}
// Don't traverse successors of recursive calls or false CFG edges.
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index 321353ca2..8aacec53f 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -105,6 +105,10 @@ impl<'tcx> Cx<'tcx> {
}
}
+ let span = match local.init {
+ Some(init) => local.span.with_hi(init.span.hi()),
+ None => local.span,
+ };
let stmt = Stmt {
kind: StmtKind::Let {
remainder_scope,
@@ -116,6 +120,7 @@ impl<'tcx> Cx<'tcx> {
initializer: local.init.map(|init| self.mirror_expr(init)),
else_block,
lint_level: LintLevel::Explicit(local.hir_id),
+ span,
},
opt_destruction_scope: opt_dxn_ext,
};
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 9086412c0..8e2e92e6f 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -10,7 +10,7 @@ use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
use rustc_middle::middle::region;
-use rustc_middle::mir::{self, BinOp, BorrowKind, Field, UnOp};
+use rustc_middle::mir::{self, BinOp, BorrowKind, UnOp};
use rustc_middle::thir::*;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -20,7 +20,7 @@ use rustc_middle::ty::{
self, AdtKind, InlineConstSubsts, InlineConstSubstsParts, ScalarInt, Ty, UpvarSubsts, UserType,
};
use rustc_span::{sym, Span};
-use rustc_target::abi::VariantIdx;
+use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
impl<'tcx> Cx<'tcx> {
pub(crate) fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId {
@@ -185,7 +185,7 @@ impl<'tcx> Cx<'tcx> {
if self.typeck_results().is_coercion_cast(source.hir_id) {
// Convert the lexpr to a vexpr.
ExprKind::Use { source: self.mirror_expr(source) }
- } else if self.typeck_results().expr_ty(source).is_region_ptr() {
+ } else if self.typeck_results().expr_ty(source).is_ref() {
// Special cased so that we can type check that the element
// type of the source matches the pointed to type of the
// destination.
@@ -357,7 +357,7 @@ impl<'tcx> Cx<'tcx> {
Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => {
Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id)))
}
- Res::SelfCtor(..) => Some((adt_def, VariantIdx::new(0))),
+ Res::SelfCtor(..) => Some((adt_def, FIRST_VARIANT)),
_ => None,
})
} else {
@@ -379,7 +379,7 @@ impl<'tcx> Cx<'tcx> {
.iter()
.enumerate()
.map(|(idx, e)| FieldExpr {
- name: Field::new(idx),
+ name: FieldIdx::new(idx),
expr: self.mirror_expr(e),
})
.collect();
@@ -510,7 +510,7 @@ impl<'tcx> Cx<'tcx> {
debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
ExprKind::Adt(Box::new(AdtExpr {
adt_def: *adt,
- variant_index: VariantIdx::new(0),
+ variant_index: FIRST_VARIANT,
substs,
user_ty,
fields: self.field_refs(fields),
@@ -732,8 +732,8 @@ impl<'tcx> Cx<'tcx> {
}
hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
lhs: self.mirror_expr(source),
- variant_index: VariantIdx::new(0),
- name: Field::new(self.typeck_results.field_index(expr.hir_id)),
+ variant_index: FIRST_VARIANT,
+ name: self.typeck_results.field_index(expr.hir_id),
},
hir::ExprKind::Cast(ref source, ref cast_ty) => {
// Check for a user-given type annotation on this `cast`
@@ -780,7 +780,6 @@ impl<'tcx> Cx<'tcx> {
hir::ExprKind::DropTemps(ref source) => {
ExprKind::Use { source: self.mirror_expr(source) }
}
- hir::ExprKind::Box(ref value) => ExprKind::Box { value: self.mirror_expr(value) },
hir::ExprKind::Array(ref fields) => {
ExprKind::Array { fields: self.mirror_exprs(fields) }
}
@@ -1054,7 +1053,7 @@ impl<'tcx> Cx<'tcx> {
HirProjectionKind::Field(field, variant_index) => ExprKind::Field {
lhs: self.thir.exprs.push(captured_place_expr),
variant_index,
- name: Field::new(field as usize),
+ name: field,
},
HirProjectionKind::Index | HirProjectionKind::Subslice => {
// We don't capture these projections, so we can ignore them here
@@ -1108,7 +1107,7 @@ impl<'tcx> Cx<'tcx> {
fields
.iter()
.map(|field| FieldExpr {
- name: Field::new(self.typeck_results.field_index(field.hir_id)),
+ name: self.typeck_results.field_index(field.hir_id),
expr: self.mirror_expr(field.expr),
})
.collect()
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 2640ca56b..8f58db504 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -2,45 +2,48 @@ use super::deconstruct_pat::{Constructor, DeconstructedPat};
use super::usefulness::{
compute_match_usefulness, MatchArm, MatchCheckCtxt, Reachability, UsefulnessReport,
};
-use super::{PatCtxt, PatternError};
use crate::errors::*;
-use hir::{ExprKind, PatKind};
use rustc_arena::TypedArena;
-use rustc_ast::{LitKind, Mutability};
+use rustc_ast::Mutability;
+use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::*;
-use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{HirId, Pat};
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::HirId;
+use rustc_middle::thir::visit::{self, Visitor};
+use rustc_middle::thir::*;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
-
use rustc_session::lint::builtin::{
BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
};
use rustc_session::Session;
-use rustc_span::source_map::Spanned;
-use rustc_span::{BytePos, Span};
-
-pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
- let body_id = match def_id.as_local() {
- None => return,
- Some(def_id) => tcx.hir().body_owned_by(def_id),
- };
+use rustc_span::hygiene::DesugaringKind;
+use rustc_span::Span;
+pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+ let Ok((thir, expr)) = tcx.thir_body(ty::WithOptConstParam::unknown(def_id)) else { return };
+ let thir = thir.borrow();
let pattern_arena = TypedArena::default();
let mut visitor = MatchVisitor {
tcx,
- typeck_results: tcx.typeck_body(body_id),
+ thir: &*thir,
param_env: tcx.param_env(def_id),
+ lint_level: tcx.hir().local_def_id_to_hir_id(def_id),
+ let_source: LetSource::None,
pattern_arena: &pattern_arena,
};
- visitor.visit_body(tcx.hir().body(body_id));
+ visitor.visit_expr(&thir[expr]);
+ for param in thir.params.iter() {
+ if let Some(box ref pattern) = param.pat {
+ visitor.check_irrefutable(pattern, "function argument", None);
+ }
+ }
}
fn create_e0004(
@@ -58,77 +61,132 @@ enum RefutableFlag {
}
use RefutableFlag::*;
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum LetSource {
+ None,
+ IfLet,
+ IfLetGuard,
+ LetElse,
+ WhileLet,
+}
+
struct MatchVisitor<'a, 'p, 'tcx> {
tcx: TyCtxt<'tcx>,
- typeck_results: &'a ty::TypeckResults<'tcx>,
param_env: ty::ParamEnv<'tcx>,
+ thir: &'a Thir<'tcx>,
+ lint_level: HirId,
+ let_source: LetSource,
pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
}
-impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
- fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
- intravisit::walk_expr(self, ex);
- match &ex.kind {
- hir::ExprKind::Match(scrut, arms, source) => {
- self.check_match(scrut, arms, *source, ex.span)
+impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> {
+ fn thir(&self) -> &'a Thir<'tcx> {
+ self.thir
+ }
+
+ #[instrument(level = "trace", skip(self))]
+ fn visit_arm(&mut self, arm: &Arm<'tcx>) {
+ match arm.guard {
+ Some(Guard::If(expr)) => {
+ self.with_let_source(LetSource::IfLetGuard, |this| {
+ this.visit_expr(&this.thir[expr])
+ });
}
- hir::ExprKind::Let(hir::Let { pat, init, span, .. }) => {
- self.check_let(pat, init, *span)
+ Some(Guard::IfLet(ref pat, expr)) => {
+ self.with_let_source(LetSource::IfLetGuard, |this| {
+ this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
+ this.visit_pat(pat);
+ this.visit_expr(&this.thir[expr]);
+ });
}
- _ => {}
+ None => {}
}
+ self.visit_pat(&arm.pattern);
+ self.visit_expr(&self.thir[arm.body]);
}
- fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) {
- intravisit::walk_local(self, loc);
- let els = loc.els;
- if let Some(init) = loc.init && els.is_some() {
- // Build a span without the else { ... } as we don't want to underline
- // the entire else block in the IDE setting.
- let span = loc.span.with_hi(init.span.hi());
- self.check_let(&loc.pat, init, span);
- }
-
- let (msg, sp) = match loc.source {
- hir::LocalSource::Normal => ("local binding", Some(loc.span)),
- hir::LocalSource::AsyncFn => ("async fn binding", None),
- hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
- hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None),
+ #[instrument(level = "trace", skip(self))]
+ fn visit_expr(&mut self, ex: &Expr<'tcx>) {
+ match ex.kind {
+ ExprKind::Scope { value, lint_level, .. } => {
+ let old_lint_level = self.lint_level;
+ if let LintLevel::Explicit(hir_id) = lint_level {
+ self.lint_level = hir_id;
+ }
+ self.visit_expr(&self.thir[value]);
+ self.lint_level = old_lint_level;
+ return;
+ }
+ ExprKind::If { cond, then, else_opt, if_then_scope: _ } => {
+ // Give a specific `let_source` for the condition.
+ let let_source = match ex.span.desugaring_kind() {
+ Some(DesugaringKind::WhileLoop) => LetSource::WhileLet,
+ _ => LetSource::IfLet,
+ };
+ self.with_let_source(let_source, |this| this.visit_expr(&self.thir[cond]));
+ self.with_let_source(LetSource::None, |this| {
+ this.visit_expr(&this.thir[then]);
+ if let Some(else_) = else_opt {
+ this.visit_expr(&this.thir[else_]);
+ }
+ });
+ return;
+ }
+ ExprKind::Match { scrutinee, box ref arms } => {
+ let source = match ex.span.desugaring_kind() {
+ Some(DesugaringKind::ForLoop) => hir::MatchSource::ForLoopDesugar,
+ Some(DesugaringKind::QuestionMark) => hir::MatchSource::TryDesugar,
+ Some(DesugaringKind::Await) => hir::MatchSource::AwaitDesugar,
+ _ => hir::MatchSource::Normal,
+ };
+ self.check_match(scrutinee, arms, source, ex.span);
+ }
+ ExprKind::Let { box ref pat, expr } => {
+ self.check_let(pat, expr, self.let_source, ex.span);
+ }
+ ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => {
+ self.check_let_chain(self.let_source, ex.span, lhs, rhs);
+ }
+ _ => {}
};
- if els.is_none() {
- self.check_irrefutable(&loc.pat, msg, sp);
- }
+ self.with_let_source(LetSource::None, |this| visit::walk_expr(this, ex));
}
- fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
- intravisit::walk_param(self, param);
- self.check_irrefutable(&param.pat, "function argument", None);
- }
-}
-
-impl PatCtxt<'_, '_> {
- fn report_inlining_errors(&self) {
- for error in &self.errors {
- match *error {
- PatternError::StaticInPattern(span) => {
- self.tcx.sess.emit_err(StaticInPattern { span });
+ fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) {
+ let old_lint_level = self.lint_level;
+ match stmt.kind {
+ StmtKind::Let {
+ box ref pattern, initializer, else_block, lint_level, span, ..
+ } => {
+ if let LintLevel::Explicit(lint_level) = lint_level {
+ self.lint_level = lint_level;
}
- PatternError::AssocConstInPattern(span) => {
- self.tcx.sess.emit_err(AssocConstInPattern { span });
- }
- PatternError::ConstParamInPattern(span) => {
- self.tcx.sess.emit_err(ConstParamInPattern { span });
+
+ if let Some(initializer) = initializer && else_block.is_some() {
+ self.check_let(pattern, initializer, LetSource::LetElse, span);
}
- PatternError::NonConstPath(span) => {
- self.tcx.sess.emit_err(NonConstPath { span });
+
+ if else_block.is_none() {
+ self.check_irrefutable(pattern, "local binding", Some(span));
}
}
+ _ => {}
}
+ visit::walk_stmt(self, stmt);
+ self.lint_level = old_lint_level;
}
}
impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
- fn check_patterns(&self, pat: &Pat<'_>, rf: RefutableFlag) {
+ #[instrument(level = "trace", skip(self, f))]
+ fn with_let_source(&mut self, let_source: LetSource, f: impl FnOnce(&mut Self)) {
+ let old_let_source = self.let_source;
+ self.let_source = let_source;
+ ensure_sufficient_stack(|| f(self));
+ self.let_source = old_let_source;
+ }
+
+ fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) {
pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
check_for_bindings_named_same_as_variants(self, pat, rf);
}
@@ -136,73 +194,63 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
fn lower_pattern(
&self,
cx: &mut MatchCheckCtxt<'p, 'tcx>,
- pat: &'tcx hir::Pat<'tcx>,
- have_errors: &mut bool,
+ pattern: &Pat<'tcx>,
) -> &'p DeconstructedPat<'p, 'tcx> {
- let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.typeck_results);
- patcx.include_lint_checks();
- let pattern = patcx.lower_pattern(pat);
- let pattern: &_ = cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern));
- if !patcx.errors.is_empty() {
- *have_errors = true;
- patcx.report_inlining_errors();
- }
- pattern
+ cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern))
}
- fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'p, 'tcx> {
+ fn new_cx(&self, hir_id: HirId, refutable: bool) -> MatchCheckCtxt<'p, 'tcx> {
MatchCheckCtxt {
tcx: self.tcx,
param_env: self.param_env,
module: self.tcx.parent_module(hir_id).to_def_id(),
pattern_arena: &self.pattern_arena,
+ refutable,
}
}
- fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, scrutinee: &hir::Expr<'_>, span: Span) {
+ #[instrument(level = "trace", skip(self))]
+ fn check_let(&mut self, pat: &Pat<'tcx>, scrutinee: ExprId, source: LetSource, span: Span) {
+ if let LetSource::None = source {
+ return;
+ }
self.check_patterns(pat, Refutable);
- let mut cx = self.new_cx(scrutinee.hir_id);
- let tpat = self.lower_pattern(&mut cx, pat, &mut false);
- self.check_let_reachability(&mut cx, pat.hir_id, tpat, span);
+ let mut cx = self.new_cx(self.lint_level, true);
+ let tpat = self.lower_pattern(&mut cx, pat);
+ self.check_let_reachability(&mut cx, self.lint_level, source, tpat, span);
}
fn check_match(
&mut self,
- scrut: &hir::Expr<'_>,
- hir_arms: &'tcx [hir::Arm<'tcx>],
+ scrut: ExprId,
+ arms: &[ArmId],
source: hir::MatchSource,
expr_span: Span,
) {
- let mut cx = self.new_cx(scrut.hir_id);
+ let mut cx = self.new_cx(self.lint_level, true);
- for arm in hir_arms {
+ for &arm in arms {
// Check the arm for some things unrelated to exhaustiveness.
- self.check_patterns(&arm.pat, Refutable);
- if let Some(hir::Guard::IfLet(ref let_expr)) = arm.guard {
- self.check_patterns(let_expr.pat, Refutable);
- let tpat = self.lower_pattern(&mut cx, let_expr.pat, &mut false);
- self.check_let_reachability(&mut cx, let_expr.pat.hir_id, tpat, tpat.span());
- }
+ let arm = &self.thir.arms[arm];
+ self.check_patterns(&arm.pattern, Refutable);
}
- let mut have_errors = false;
-
- let arms: Vec<_> = hir_arms
+ let tarms: Vec<_> = arms
.iter()
- .map(|hir::Arm { pat, guard, .. }| MatchArm {
- pat: self.lower_pattern(&mut cx, pat, &mut have_errors),
- hir_id: pat.hir_id,
- has_guard: guard.is_some(),
+ .map(|&arm| {
+ let arm = &self.thir.arms[arm];
+ let hir_id = match arm.lint_level {
+ LintLevel::Explicit(hir_id) => hir_id,
+ LintLevel::Inherited => self.lint_level,
+ };
+ let pat = self.lower_pattern(&mut cx, &arm.pattern);
+ MatchArm { pat, hir_id, has_guard: arm.guard.is_some() }
})
.collect();
- // Bail out early if lowering failed.
- if have_errors {
- return;
- }
-
- let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut);
- let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty);
+ let scrut = &self.thir[scrut];
+ let scrut_ty = scrut.ty;
+ let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty);
match source {
// Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
@@ -219,12 +267,18 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
// Check if the match is exhaustive.
let witnesses = report.non_exhaustiveness_witnesses;
if !witnesses.is_empty() {
- if source == hir::MatchSource::ForLoopDesugar && hir_arms.len() == 2 {
+ if source == hir::MatchSource::ForLoopDesugar && arms.len() == 2 {
// the for loop pattern is not irrefutable
- let pat = hir_arms[1].pat.for_loop_some().unwrap();
- self.check_irrefutable(pat, "`for` loop binding", None);
+ let pat = &self.thir[arms[1]].pattern;
+ // `pat` should be `Some(<pat_field>)` from a desugared for loop.
+ debug_assert_eq!(pat.span.desugaring_kind(), Some(DesugaringKind::ForLoop));
+ let PatKind::Variant { ref subpatterns, .. } = pat.kind else { bug!() };
+ let [pat_field] = &subpatterns[..] else { bug!() };
+ self.check_irrefutable(&pat_field.pattern, "`for` loop binding", None);
} else {
- non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, hir_arms, expr_span);
+ non_exhaustive_match(
+ &cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span,
+ );
}
}
}
@@ -233,114 +287,93 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
&mut self,
cx: &mut MatchCheckCtxt<'p, 'tcx>,
pat_id: HirId,
+ source: LetSource,
pat: &'p DeconstructedPat<'p, 'tcx>,
span: Span,
) {
- if self.check_let_chain(cx, pat_id) {
- return;
- }
-
if is_let_irrefutable(cx, pat_id, pat) {
- irrefutable_let_pattern(cx.tcx, pat_id, span);
+ irrefutable_let_patterns(cx.tcx, pat_id, source, 1, span);
}
}
- fn check_let_chain(&mut self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId) -> bool {
- let hir = self.tcx.hir();
- let parent = hir.parent_id(pat_id);
+ #[instrument(level = "trace", skip(self))]
+ fn check_let_chain(
+ &mut self,
+ let_source: LetSource,
+ top_expr_span: Span,
+ mut lhs: ExprId,
+ rhs: ExprId,
+ ) {
+ if let LetSource::None = let_source {
+ return;
+ }
- // First, figure out if the given pattern is part of a let chain,
- // and if so, obtain the top node of the chain.
- let mut top = parent;
- let mut part_of_chain = false;
- loop {
- let new_top = hir.parent_id(top);
- if let hir::Node::Expr(
- hir::Expr {
- kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, lhs, rhs),
- ..
- },
- ..,
- ) = hir.get(new_top)
- {
- // If this isn't the first iteration, we need to check
- // if there is a let expr before us in the chain, so
- // that we avoid doubly checking the let chain.
-
- // The way a chain of &&s is encoded is ((let ... && let ...) && let ...) && let ...
- // as && is left-to-right associative. Thus, we need to check rhs.
- if part_of_chain && matches!(rhs.kind, hir::ExprKind::Let(..)) {
- return true;
+ // Lint level enclosing the next `lhs`.
+ let mut cur_lint_level = self.lint_level;
+
+ // Obtain the refutabilities of all exprs in the chain,
+ // and record chain members that aren't let exprs.
+ let mut chain_refutabilities = Vec::new();
+
+ let add = |expr: ExprId, mut local_lint_level| {
+ // `local_lint_level` is the lint level enclosing the pattern inside `expr`.
+ let mut expr = &self.thir[expr];
+ debug!(?expr, ?local_lint_level, "add");
+ // Fast-forward through scopes.
+ while let ExprKind::Scope { value, lint_level, .. } = expr.kind {
+ if let LintLevel::Explicit(hir_id) = lint_level {
+ local_lint_level = hir_id
}
- // If there is a let at the lhs, and we provide the rhs, we don't do any checking either.
- if !part_of_chain && matches!(lhs.kind, hir::ExprKind::Let(..)) && rhs.hir_id == top
- {
- return true;
+ expr = &self.thir[value];
+ }
+ debug!(?expr, ?local_lint_level, "after scopes");
+ match expr.kind {
+ ExprKind::Let { box ref pat, expr: _ } => {
+ let mut ncx = self.new_cx(local_lint_level, true);
+ let tpat = self.lower_pattern(&mut ncx, pat);
+ let refutable = !is_let_irrefutable(&mut ncx, local_lint_level, tpat);
+ Some((expr.span, refutable))
}
- } else {
- // We've reached the top.
- break;
+ _ => None,
}
+ };
- // Since this function is called within a let context, it is reasonable to assume that any parent
- // `&&` infers a let chain
- part_of_chain = true;
- top = new_top;
- }
- if !part_of_chain {
- return false;
- }
+ // Let chains recurse on the left, so we start by adding the rightmost.
+ chain_refutabilities.push(add(rhs, cur_lint_level));
- // Second, obtain the refutabilities of all exprs in the chain,
- // and record chain members that aren't let exprs.
- let mut chain_refutabilities = Vec::new();
- let hir::Node::Expr(top_expr) = hir.get(top) else {
- // We ensure right above that it's an Expr
- unreachable!()
- };
- let mut cur_expr = top_expr;
loop {
- let mut add = |expr: &hir::Expr<'tcx>| {
- let refutability = match expr.kind {
- hir::ExprKind::Let(hir::Let { pat, init, span, .. }) => {
- let mut ncx = self.new_cx(init.hir_id);
- let tpat = self.lower_pattern(&mut ncx, pat, &mut false);
-
- let refutable = !is_let_irrefutable(&mut ncx, pat.hir_id, tpat);
- Some((*span, refutable))
- }
- _ => None,
- };
- chain_refutabilities.push(refutability);
- };
- if let hir::Expr {
- kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, lhs, rhs),
- ..
- } = cur_expr
+ while let ExprKind::Scope { value, lint_level, .. } = self.thir[lhs].kind {
+ if let LintLevel::Explicit(hir_id) = lint_level {
+ cur_lint_level = hir_id
+ }
+ lhs = value;
+ }
+ if let ExprKind::LogicalOp { op: LogicalOp::And, lhs: new_lhs, rhs: expr } =
+ self.thir[lhs].kind
{
- add(rhs);
- cur_expr = lhs;
+ chain_refutabilities.push(add(expr, cur_lint_level));
+ lhs = new_lhs;
} else {
- add(cur_expr);
+ chain_refutabilities.push(add(lhs, cur_lint_level));
break;
}
}
+ debug!(?chain_refutabilities);
chain_refutabilities.reverse();
// Third, emit the actual warnings.
-
if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, false)))) {
// The entire chain is made up of irrefutable `let` statements
- let let_source = let_source_parent(self.tcx, top, None);
irrefutable_let_patterns(
- cx.tcx,
- top,
+ self.tcx,
+ self.lint_level,
let_source,
chain_refutabilities.len(),
- top_expr.span,
+ top_expr_span,
);
- return true;
+ return;
}
+
if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 {
// The chain has a non-zero prefix of irrefutable `let` statements.
@@ -350,7 +383,6 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
// so can't always be moved out.
// FIXME: Add checking whether the bindings are actually used in the prefix,
// and lint if they are not.
- let let_source = let_source_parent(self.tcx, top, None);
if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
// Emit the lint
let prefix = &chain_refutabilities[..until];
@@ -358,9 +390,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
let span_end = prefix.last().unwrap().unwrap().0;
let span = span_start.to(span_end);
let count = prefix.len();
- cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, LeadingIrrefutableLetPatterns { count });
+ self.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, self.lint_level, span, LeadingIrrefutableLetPatterns { count });
}
}
+
if let Some(from) = chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) && from != (chain_refutabilities.len() - 1) {
// The chain has a non-empty suffix of irrefutable `let` statements
let suffix = &chain_refutabilities[from + 1..];
@@ -368,18 +401,18 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
let span_end = suffix.last().unwrap().unwrap().0;
let span = span_start.to(span_end);
let count = suffix.len();
- cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, TrailingIrrefutableLetPatterns { count });
+ self.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, self.lint_level, span, TrailingIrrefutableLetPatterns { count });
}
- true
}
- fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) {
- let mut cx = self.new_cx(pat.hir_id);
+ #[instrument(level = "trace", skip(self))]
+ fn check_irrefutable(&self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) {
+ let mut cx = self.new_cx(self.lint_level, false);
- let pattern = self.lower_pattern(&mut cx, pat, &mut false);
+ let pattern = self.lower_pattern(&mut cx, pat);
let pattern_ty = pattern.ty();
- let arm = MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false };
- let report = compute_match_usefulness(&cx, &[arm], pat.hir_id, pattern_ty);
+ let arm = MatchArm { pat: pattern, hir_id: self.lint_level, has_guard: false };
+ let report = compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty);
// Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We
// only care about exhaustiveness here.
@@ -390,58 +423,45 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
return;
}
- let (inform, interpreted_as_const, res_defined_here,let_suggestion, misc_suggestion) =
- if let hir::PatKind::Path(hir::QPath::Resolved(
- None,
- hir::Path {
- segments: &[hir::PathSegment { args: None, res, ident, .. }],
- ..
- },
- )) = &pat.kind
- {
- (
- None,
- Some(InterpretedAsConst {
- span: pat.span,
- article: res.article(),
- variable: ident.to_string().to_lowercase(),
- res,
- }),
- try {
- ResDefinedHere {
- def_span: cx.tcx.hir().res_span(res)?,
- res,
- }
- },
- None,
- None,
- )
- } else if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) {
- let mut bindings = vec![];
- pat.walk_always(&mut |pat: &hir::Pat<'_>| {
- if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
- bindings.push(ident);
- }
+ let inform = sp.is_some().then_some(Inform);
+ let mut let_suggestion = None;
+ let mut misc_suggestion = None;
+ let mut interpreted_as_const = None;
+ if let PatKind::Constant { .. } = pat.kind
+ && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
+ {
+ // If the pattern to match is an integer literal:
+ if snippet.chars().all(|c| c.is_digit(10)) {
+ // Then give a suggestion, the user might've meant to create a binding instead.
+ misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral {
+ start_span: pat.span.shrink_to_lo()
});
- let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1));
- let start_span = span.shrink_to_lo();
- let end_span = semi_span.shrink_to_lo();
- let count = witnesses.len();
-
- // If the pattern to match is an integer literal:
- let int_suggestion = if
- let PatKind::Lit(expr) = &pat.kind
- && bindings.is_empty()
- && let ExprKind::Lit(Spanned { node: LitKind::Int(_, _), span }) = expr.kind {
- // Then give a suggestion, the user might've meant to create a binding instead.
- Some(MiscPatternSuggestion::AttemptedIntegerLiteral { start_span: span.shrink_to_lo() })
- } else { None };
-
- let let_suggestion = if bindings.is_empty() {SuggestLet::If{start_span, semi_span, count}} else{ SuggestLet::Else{end_span, count }};
- (sp.map(|_|Inform), None, None, Some(let_suggestion), int_suggestion)
- } else{
- (sp.map(|_|Inform), None, None, None, None)
- };
+ } else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') {
+ interpreted_as_const = Some(InterpretedAsConst {
+ span: pat.span,
+ variable: snippet,
+ });
+ }
+ }
+
+ if let Some(span) = sp
+ && self.tcx.sess.source_map().is_span_accessible(span)
+ && interpreted_as_const.is_none()
+ {
+ let mut bindings = vec![];
+ pat.each_binding(|name, _, _, _| bindings.push(name));
+
+ let semi_span = span.shrink_to_hi();
+ let start_span = span.shrink_to_lo();
+ let end_span = semi_span.shrink_to_lo();
+ let count = witnesses.len();
+
+ let_suggestion = Some(if bindings.is_empty() {
+ SuggestLet::If { start_span, semi_span, count }
+ } else {
+ SuggestLet::Else { end_span, count }
+ });
+ };
let adt_defined_here = try {
let ty = pattern_ty.peel_refs();
@@ -465,7 +485,6 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
pattern_ty,
let_suggestion,
misc_suggestion,
- res_defined_here,
adt_defined_here,
});
}
@@ -477,14 +496,18 @@ fn check_for_bindings_named_same_as_variants(
rf: RefutableFlag,
) {
pat.walk_always(|p| {
- if let hir::PatKind::Binding(_, _, ident, None) = p.kind
- && let Some(ty::BindByValue(hir::Mutability::Not)) =
- cx.typeck_results.extract_binding_mode(cx.tcx.sess, p.hir_id, p.span)
- && let pat_ty = cx.typeck_results.pat_ty(p).peel_refs()
- && let ty::Adt(edef, _) = pat_ty.kind()
+ if let PatKind::Binding {
+ name,
+ mode: BindingMode::ByValue,
+ mutability: Mutability::Not,
+ subpattern: None,
+ ty,
+ ..
+ } = p.kind
+ && let ty::Adt(edef, _) = ty.peel_refs().kind()
&& edef.is_enum()
&& edef.variants().iter().any(|variant| {
- variant.ident(cx.tcx) == ident && variant.ctor_kind() == Some(CtorKind::Const)
+ variant.name == name && variant.ctor_kind() == Some(CtorKind::Const)
})
{
let variant_count = edef.variants().len();
@@ -493,7 +516,7 @@ fn check_for_bindings_named_same_as_variants(
});
cx.tcx.emit_spanned_lint(
BINDINGS_WITH_VARIANT_NAME,
- p.hir_id,
+ cx.lint_level,
p.span,
BindingsWithVariantName {
// If this is an irrefutable pattern, and there's > 1 variant,
@@ -503,7 +526,7 @@ fn check_for_bindings_named_same_as_variants(
Some(p.span)
} else { None },
ty_path,
- ident,
+ name,
},
)
}
@@ -529,11 +552,6 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<
);
}
-fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) {
- let source = let_source(tcx, id);
- irrefutable_let_patterns(tcx, id, source, 1, span);
-}
-
fn irrefutable_let_patterns(
tcx: TyCtxt<'_>,
id: HirId,
@@ -548,7 +566,7 @@ fn irrefutable_let_patterns(
}
match source {
- LetSource::GenericLet => emit_diag!(IrrefutableLetPatternsGenericLet),
+ LetSource::None => bug!(),
LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet),
LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard),
LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse),
@@ -604,10 +622,11 @@ fn report_arm_reachability<'p, 'tcx>(
/// Report that a match is not exhaustive.
fn non_exhaustive_match<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
+ thir: &Thir<'tcx>,
scrut_ty: Ty<'tcx>,
sp: Span,
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
- arms: &[hir::Arm<'tcx>],
+ arms: &[ArmId],
expr_span: Span,
) {
let is_empty_match = arms.is_empty();
@@ -705,6 +724,7 @@ fn non_exhaustive_match<'p, 'tcx>(
));
}
[only] => {
+ let only = &thir[*only];
let (pre_indentation, is_multiline) = if let Some(snippet) = sm.indentation_before(only.span)
&& let Ok(with_trailing) = sm.span_extend_while(only.span, |c| c.is_whitespace() || c == ',')
&& sm.is_multiline(with_trailing)
@@ -713,8 +733,9 @@ fn non_exhaustive_match<'p, 'tcx>(
} else {
(" ".to_string(), false)
};
- let comma = if matches!(only.body.kind, hir::ExprKind::Block(..))
- && only.span.eq_ctxt(only.body.span)
+ let only_body = &thir[only.body];
+ let comma = if matches!(only_body.kind, ExprKind::Block { .. })
+ && only.span.eq_ctxt(only_body.span)
&& is_multiline
{
""
@@ -726,24 +747,29 @@ fn non_exhaustive_match<'p, 'tcx>(
format!("{}{}{} => todo!()", comma, pre_indentation, pattern),
));
}
- [.., prev, last] if prev.span.eq_ctxt(last.span) => {
- let comma = if matches!(last.body.kind, hir::ExprKind::Block(..))
- && last.span.eq_ctxt(last.body.span)
- {
- ""
- } else {
- ","
- };
- let spacing = if sm.is_multiline(prev.span.between(last.span)) {
- sm.indentation_before(last.span).map(|indent| format!("\n{indent}"))
- } else {
- Some(" ".to_string())
- };
- if let Some(spacing) = spacing {
- suggestion = Some((
- last.span.shrink_to_hi(),
- format!("{}{}{} => todo!()", comma, spacing, pattern),
- ));
+ [.., prev, last] => {
+ let prev = &thir[*prev];
+ let last = &thir[*last];
+ if prev.span.eq_ctxt(last.span) {
+ let last_body = &thir[last.body];
+ let comma = if matches!(last_body.kind, ExprKind::Block { .. })
+ && last.span.eq_ctxt(last_body.span)
+ {
+ ""
+ } else {
+ ","
+ };
+ let spacing = if sm.is_multiline(prev.span.between(last.span)) {
+ sm.indentation_before(last.span).map(|indent| format!("\n{indent}"))
+ } else {
+ Some(" ".to_string())
+ };
+ if let Some(spacing) = spacing {
+ suggestion = Some((
+ last.span.shrink_to_hi(),
+ format!("{}{}{} => todo!()", comma, spacing, pattern),
+ ));
+ }
}
}
_ => {}
@@ -863,10 +889,6 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>(
}
/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
-fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId) -> bool {
- !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx, cx.param_env)
-}
-
/// Check that there are no borrow or move conflicts in `binding @ subpat` patterns.
///
/// For example, this would reject:
@@ -877,45 +899,36 @@ fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId) -> bool {
/// - `x @ Some(ref mut? y)`.
///
/// This analysis is *not* subsumed by NLL.
-fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pat<'_>) {
+fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, pat: &Pat<'tcx>) {
// Extract `sub` in `binding @ sub`.
- let (name, sub) = match &pat.kind {
- hir::PatKind::Binding(.., name, Some(sub)) => (*name, sub),
- _ => return,
- };
- let binding_span = pat.span.with_hi(name.span.hi());
+ let PatKind::Binding { name, mode, ty, subpattern: Some(box ref sub), .. } = pat.kind else { return };
+
+ let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env);
- let typeck_results = cx.typeck_results;
let sess = cx.tcx.sess;
// Get the binding move, extract the mutability if by-ref.
- let mut_outer = match typeck_results.extract_binding_mode(sess, pat.hir_id, pat.span) {
- Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id) => {
+ let mut_outer = match mode {
+ BindingMode::ByValue if is_binding_by_move(ty) => {
// We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
let mut conflicts_ref = Vec::new();
- sub.each_binding(|_, hir_id, span, _| {
- match typeck_results.extract_binding_mode(sess, hir_id, span) {
- Some(ty::BindByValue(_)) | None => {}
- Some(ty::BindByReference(_)) => conflicts_ref.push(span),
- }
+ sub.each_binding(|_, mode, _, span| match mode {
+ BindingMode::ByValue => {}
+ BindingMode::ByRef(_) => conflicts_ref.push(span),
});
if !conflicts_ref.is_empty() {
sess.emit_err(BorrowOfMovedValue {
- span: pat.span,
- binding_span,
+ binding_span: pat.span,
conflicts_ref,
name,
- ty: typeck_results.node_type(pat.hir_id),
- suggest_borrowing: pat
- .span
- .contains(binding_span)
- .then(|| binding_span.shrink_to_lo()),
+ ty,
+ suggest_borrowing: Some(pat.span.shrink_to_lo()),
});
}
return;
}
- Some(ty::BindByValue(_)) | None => return,
- Some(ty::BindByReference(m)) => m,
+ BindingMode::ByValue => return,
+ BindingMode::ByRef(m) => m.mutability(),
};
// We now have `ref $mut_outer binding @ sub` (semantically).
@@ -923,9 +936,9 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
let mut conflicts_move = Vec::new();
let mut conflicts_mut_mut = Vec::new();
let mut conflicts_mut_ref = Vec::new();
- sub.each_binding(|_, hir_id, span, name| {
- match typeck_results.extract_binding_mode(sess, hir_id, span) {
- Some(ty::BindByReference(mut_inner)) => match (mut_outer, mut_inner) {
+ sub.each_binding(|name, mode, ty, span| {
+ match mode {
+ BindingMode::ByRef(mut_inner) => match (mut_outer, mut_inner.mutability()) {
// Both sides are `ref`.
(Mutability::Not, Mutability::Not) => {}
// 2x `ref mut`.
@@ -939,10 +952,10 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
conflicts_mut_ref.push(Conflict::Ref { span, name })
}
},
- Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => {
+ BindingMode::ByValue if is_binding_by_move(ty) => {
conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict.
}
- Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine.
+ BindingMode::ByValue => {} // `ref mut?` + by-copy is fine.
}
});
@@ -950,92 +963,30 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
let report_mut_ref = !conflicts_mut_ref.is_empty();
let report_move_conflict = !conflicts_move.is_empty();
- let mut occurences = match mut_outer {
- Mutability::Mut => vec![Conflict::Mut { span: binding_span, name }],
- Mutability::Not => vec![Conflict::Ref { span: binding_span, name }],
+ let mut occurrences = match mut_outer {
+ Mutability::Mut => vec![Conflict::Mut { span: pat.span, name }],
+ Mutability::Not => vec![Conflict::Ref { span: pat.span, name }],
};
- occurences.extend(conflicts_mut_mut);
- occurences.extend(conflicts_mut_ref);
- occurences.extend(conflicts_move);
+ occurrences.extend(conflicts_mut_mut);
+ occurrences.extend(conflicts_mut_ref);
+ occurrences.extend(conflicts_move);
// Report errors if any.
if report_mut_mut {
// Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
- sess.emit_err(MultipleMutBorrows { span: pat.span, occurences });
+ sess.emit_err(MultipleMutBorrows { span: pat.span, occurrences });
} else if report_mut_ref {
// Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
match mut_outer {
Mutability::Mut => {
- sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurences });
+ sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurrences });
}
Mutability::Not => {
- sess.emit_err(AlreadyBorrowed { span: pat.span, occurences });
+ sess.emit_err(AlreadyBorrowed { span: pat.span, occurrences });
}
};
} else if report_move_conflict {
// Report by-ref and by-move conflicts, e.g. `ref x @ y`.
- sess.emit_err(MovedWhileBorrowed { span: pat.span, occurences });
- }
-}
-
-#[derive(Clone, Copy, Debug)]
-pub enum LetSource {
- GenericLet,
- IfLet,
- IfLetGuard,
- LetElse,
- WhileLet,
-}
-
-fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
- let hir = tcx.hir();
-
- let parent = hir.parent_id(pat_id);
- let_source_parent(tcx, parent, Some(pat_id))
-}
-
-fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> LetSource {
- let hir = tcx.hir();
-
- let parent_node = hir.get(parent);
-
- match parent_node {
- hir::Node::Arm(hir::Arm {
- guard: Some(hir::Guard::IfLet(&hir::Let { pat: hir::Pat { hir_id, .. }, .. })),
- ..
- }) if Some(*hir_id) == pat_id => {
- return LetSource::IfLetGuard;
- }
- _ => {}
- }
-
- let parent_parent = hir.parent_id(parent);
- let parent_parent_node = hir.get(parent_parent);
- match parent_parent_node {
- hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), .. }) => {
- return LetSource::LetElse;
- }
- hir::Node::Arm(hir::Arm { guard: Some(hir::Guard::If(_)), .. }) => {
- return LetSource::IfLetGuard;
- }
- _ => {}
+ sess.emit_err(MovedWhileBorrowed { span: pat.span, occurrences });
}
-
- let parent_parent_parent = hir.parent_id(parent_parent);
- let parent_parent_parent_parent = hir.parent_id(parent_parent_parent);
- let parent_parent_parent_parent_node = hir.get(parent_parent_parent_parent);
-
- if let hir::Node::Expr(hir::Expr {
- kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _),
- ..
- }) = parent_parent_parent_parent_node
- {
- return LetSource::WhileLet;
- }
-
- if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If(..), .. }) = parent_parent_node {
- return LetSource::IfLet;
- }
-
- LetSource::GenericLet
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index ff88d0013..32d0404bd 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,14 +1,15 @@
use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
-use rustc_middle::mir::{self, Field};
+use rustc_infer::traits::Obligation;
+use rustc_middle::mir;
use rustc_middle::thir::{FieldPat, Pat, PatKind};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint;
use rustc_span::Span;
-use rustc_trait_selection::traits::predicate_for_trait_def;
+use rustc_target::abi::FieldIdx;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
+use rustc_trait_selection::traits::{self, ObligationCause};
use std::cell::Cell;
@@ -58,8 +59,6 @@ struct ConstToPat<'tcx> {
// inference context used for checking `T: Structural` bounds.
infcx: InferCtxt<'tcx>,
- include_lint_checks: bool,
-
treat_byte_string_as_slice: bool,
}
@@ -92,7 +91,6 @@ impl<'tcx> ConstToPat<'tcx> {
span,
infcx,
param_env: pat_ctxt.param_env,
- include_lint_checks: pat_ctxt.include_lint_checks,
saw_const_match_error: Cell::new(false),
saw_const_match_lint: Cell::new(false),
behind_reference: Cell::new(false),
@@ -133,7 +131,7 @@ impl<'tcx> ConstToPat<'tcx> {
})
});
- if self.include_lint_checks && !self.saw_const_match_error.get() {
+ if !self.saw_const_match_error.get() {
// If we were able to successfully convert the const to some pat,
// double-check that all types in the const implement `Structural`.
@@ -189,17 +187,15 @@ impl<'tcx> ConstToPat<'tcx> {
// using `PartialEq::eq` in this scenario in the past.)
let partial_eq_trait_id =
self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span));
- let obligation: PredicateObligation<'_> = predicate_for_trait_def(
+ let partial_eq_obligation = Obligation::new(
self.tcx(),
+ ObligationCause::dummy(),
self.param_env,
- ObligationCause::misc(self.span, self.id.owner.def_id),
- partial_eq_trait_id,
- 0,
- [ty, ty],
+ self.tcx().mk_trait_ref(partial_eq_trait_id, [ty, ty]),
);
- // FIXME: should this call a `predicate_must_hold` variant instead?
- let has_impl = self.infcx.predicate_may_hold(&obligation);
+ // FIXME: should this call a `predicate_must_hold` variant instead?
+ let has_impl = self.infcx.predicate_may_hold(&partial_eq_obligation);
// Note: To fix rust-lang/rust#65466, we could just remove this type
// walk hack for function pointers, and unconditionally error
@@ -220,7 +216,7 @@ impl<'tcx> ConstToPat<'tcx> {
) -> Result<Vec<FieldPat<'tcx>>, FallbackToConstRef> {
vals.enumerate()
.map(|(idx, val)| {
- let field = Field::new(idx);
+ let field = FieldIdx::new(idx);
Ok(FieldPat { field, pattern: self.recur(val, false)? })
})
.collect()
@@ -240,21 +236,19 @@ impl<'tcx> ConstToPat<'tcx> {
let kind = match cv.ty().kind() {
ty::Float(_) => {
- if self.include_lint_checks {
tcx.emit_spanned_lint(
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
id,
span,
FloatPattern,
);
- }
PatKind::Constant { value: cv }
}
ty::Adt(adt_def, _) if adt_def.is_union() => {
// Matching on union fields is unsafe, we can't hide it in constants
self.saw_const_match_error.set(true);
let err = UnionPattern { span };
- tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
+ tcx.sess.emit_err(err);
PatKind::Wild
}
ty::Adt(..)
@@ -268,7 +262,7 @@ impl<'tcx> ConstToPat<'tcx> {
{
self.saw_const_match_error.set(true);
let err = TypeNotStructural { span, non_sm_ty };
- tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
+ tcx.sess.emit_err(err);
PatKind::Wild
}
// If the type is not structurally comparable, just emit the constant directly,
@@ -281,8 +275,7 @@ impl<'tcx> ConstToPat<'tcx> {
// Backwards compatibility hack because we can't cause hard errors on these
// types, so we compare them via `PartialEq::eq` at runtime.
ty::Adt(..) if !self.type_marked_structural(cv.ty()) && self.behind_reference.get() => {
- if self.include_lint_checks
- && !self.saw_const_match_error.get()
+ if !self.saw_const_match_error.get()
&& !self.saw_const_match_lint.get()
{
self.saw_const_match_lint.set(true);
@@ -306,7 +299,7 @@ impl<'tcx> ConstToPat<'tcx> {
);
self.saw_const_match_error.set(true);
let err = TypeNotStructural { span, non_sm_ty: cv.ty() };
- tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
+ tcx.sess.emit_err(err);
PatKind::Wild
}
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
@@ -340,7 +333,7 @@ impl<'tcx> ConstToPat<'tcx> {
ty::Dynamic(..) => {
self.saw_const_match_error.set(true);
let err = InvalidPattern { span, non_sm_ty: cv.ty() };
- tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
+ tcx.sess.emit_err(err);
PatKind::Wild
}
// `&str` is represented as `ConstValue::Slice`, let's keep using this
@@ -407,8 +400,7 @@ impl<'tcx> ConstToPat<'tcx> {
// to figure out how to get a reference again.
ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => {
if self.behind_reference.get() {
- if self.include_lint_checks
- && !self.saw_const_match_error.get()
+ if !self.saw_const_match_error.get()
&& !self.saw_const_match_lint.get()
{
self.saw_const_match_lint.set(true);
@@ -424,7 +416,7 @@ impl<'tcx> ConstToPat<'tcx> {
if !self.saw_const_match_error.get() {
self.saw_const_match_error.set(true);
let err = TypeNotStructural { span, non_sm_ty: *pointee_ty };
- tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
+ tcx.sess.emit_err(err);
}
PatKind::Wild
}
@@ -438,7 +430,7 @@ impl<'tcx> ConstToPat<'tcx> {
// (except slices, which are handled in a separate arm above).
let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
- tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
+ tcx.sess.emit_err(err);
PatKind::Wild
} else {
@@ -466,8 +458,7 @@ impl<'tcx> ConstToPat<'tcx> {
// compilation choices change the runtime behaviour of the match.
// See https://github.com/rust-lang/rust/issues/70861 for examples.
ty::FnPtr(..) | ty::RawPtr(..) => {
- if self.include_lint_checks
- && !self.saw_const_match_error.get()
+ if !self.saw_const_match_error.get()
&& !self.saw_const_match_lint.get()
{
self.saw_const_match_lint.set(true);
@@ -483,13 +474,12 @@ impl<'tcx> ConstToPat<'tcx> {
_ => {
self.saw_const_match_error.set(true);
let err = InvalidPattern { span, non_sm_ty: cv.ty() };
- tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
+ tcx.sess.emit_err(err);
PatKind::Wild
}
};
- if self.include_lint_checks
- && !self.saw_const_match_error.get()
+ if !self.saw_const_match_error.get()
&& !self.saw_const_match_lint.get()
&& mir_structural_match_violation
// FIXME(#73448): Find a way to bring const qualification into parity with
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index e5b7d685c..7c2919644 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -53,14 +53,14 @@ use smallvec::{smallvec, SmallVec};
use rustc_data_structures::captures::Captures;
use rustc_hir::{HirId, RangeEnd};
use rustc_index::vec::Idx;
-use rustc_middle::mir::{self, Field};
+use rustc_middle::mir;
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
use rustc_middle::{middle::stability::EvalResult, mir::interpret::ConstValue};
use rustc_session::lint;
use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::{Integer, Size, VariantIdx};
+use rustc_target::abi::{FieldIdx, Integer, Size, VariantIdx, FIRST_VARIANT};
use self::Constructor::*;
use self::SliceKind::*;
@@ -258,7 +258,7 @@ impl IntRange {
pcx: &PatCtxt<'_, 'p, 'tcx>,
pats: impl Iterator<Item = &'a DeconstructedPat<'p, 'tcx>>,
column_count: usize,
- hir_id: HirId,
+ lint_root: HirId,
) {
if self.is_singleton() {
return;
@@ -290,7 +290,7 @@ impl IntRange {
if !overlap.is_empty() {
pcx.cx.tcx.emit_spanned_lint(
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
- hir_id,
+ lint_root,
pcx.span,
OverlappingRangeEndpoints { overlap, range: pcx.span },
);
@@ -706,7 +706,7 @@ impl<'tcx> Constructor<'tcx> {
Variant(idx) => idx,
Single => {
assert!(!adt.is_enum());
- VariantIdx::new(0)
+ FIRST_VARIANT
}
_ => bug!("bad constructor {:?} for adt {:?}", self, adt),
}
@@ -1126,7 +1126,7 @@ impl<'tcx> SplitWildcard<'tcx> {
/// Note that the number of fields of a constructor may not match the fields declared in the
/// original struct/variant. This happens if a private or `non_exhaustive` field is uninhabited,
/// because the code mustn't observe that it is uninhabited. In that case that field is not
-/// included in `fields`. For that reason, when you have a `mir::Field` you must use
+/// included in `fields`. For that reason, when you have a `FieldIdx` you must use
/// `index_with_declared_idx`.
#[derive(Debug, Clone, Copy)]
pub(super) struct Fields<'p, 'tcx> {
@@ -1154,8 +1154,9 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
fn wildcards_from_tys(
cx: &MatchCheckCtxt<'p, 'tcx>,
tys: impl IntoIterator<Item = Ty<'tcx>>,
+ span: Span,
) -> Self {
- Fields::from_iter(cx, tys.into_iter().map(DeconstructedPat::wildcard))
+ Fields::from_iter(cx, tys.into_iter().map(|ty| DeconstructedPat::wildcard(ty, span)))
}
// In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide
@@ -1165,7 +1166,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
cx: &'a MatchCheckCtxt<'p, 'tcx>,
ty: Ty<'tcx>,
variant: &'a VariantDef,
- ) -> impl Iterator<Item = (Field, Ty<'tcx>)> + Captures<'a> + Captures<'p> {
+ ) -> impl Iterator<Item = (FieldIdx, Ty<'tcx>)> + Captures<'a> + Captures<'p> {
let ty::Adt(adt, substs) = ty.kind() else { bug!() };
// Whether we must not match the fields of this variant exhaustively.
let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did().is_local();
@@ -1180,7 +1181,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
if is_uninhabited && (!is_visible || is_non_exhaustive) {
None
} else {
- Some((Field::new(i), ty))
+ Some((FieldIdx::new(i), ty))
}
})
}
@@ -1191,18 +1192,18 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
pub(super) fn wildcards(pcx: &PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
let ret = match constructor {
Single | Variant(_) => match pcx.ty.kind() {
- ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()),
- ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)),
+ ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter(), pcx.span),
+ ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty), pcx.span),
ty::Adt(adt, substs) => {
if adt.is_box() {
// The only legal patterns of type `Box` (outside `std`) are `_` and box
// patterns. If we're here we can assume this is a box pattern.
- Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0)))
+ Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0)), pcx.span)
} else {
let variant = &adt.variant(constructor.variant_index_for_adt(*adt));
let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant)
.map(|(_, ty)| ty);
- Fields::wildcards_from_tys(pcx.cx, tys)
+ Fields::wildcards_from_tys(pcx.cx, tys, pcx.span)
}
}
_ => bug!("Unexpected type for `Single` constructor: {:?}", pcx),
@@ -1210,7 +1211,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
Slice(slice) => match *pcx.ty.kind() {
ty::Slice(ty) | ty::Array(ty, _) => {
let arity = slice.arity();
- Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty))
+ Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty), pcx.span)
}
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
},
@@ -1251,8 +1252,8 @@ pub(crate) struct DeconstructedPat<'p, 'tcx> {
}
impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
- pub(super) fn wildcard(ty: Ty<'tcx>) -> Self {
- Self::new(Wildcard, Fields::empty(), ty, DUMMY_SP)
+ pub(super) fn wildcard(ty: Ty<'tcx>, span: Span) -> Self {
+ Self::new(Wildcard, Fields::empty(), ty, span)
}
pub(super) fn new(
@@ -1269,7 +1270,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
/// `Some(_)`.
pub(super) fn wild_from_ctor(pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
let fields = Fields::wildcards(pcx, &ctor);
- DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP)
+ DeconstructedPat::new(ctor, fields, pcx.ty, pcx.span)
}
/// Clone this value. This method emphasizes that cloning loses reachability information and
@@ -1298,7 +1299,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
ty::Tuple(fs) => {
ctor = Single;
let mut wilds: SmallVec<[_; 2]> =
- fs.iter().map(DeconstructedPat::wildcard).collect();
+ fs.iter().map(|ty| DeconstructedPat::wildcard(ty, pat.span)).collect();
for pat in subpatterns {
wilds[pat.field.index()] = mkpat(&pat.pattern);
}
@@ -1317,11 +1318,11 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
// normally or through box-patterns. We'll have to figure out a proper
// solution when we introduce generalized deref patterns. Also need to
// prevent mixing of those two options.
- let pat = subpatterns.into_iter().find(|pat| pat.field.index() == 0);
- let pat = if let Some(pat) = pat {
+ let pattern = subpatterns.into_iter().find(|pat| pat.field.index() == 0);
+ let pat = if let Some(pat) = pattern {
mkpat(&pat.pattern)
} else {
- DeconstructedPat::wildcard(substs.type_at(0))
+ DeconstructedPat::wildcard(substs.type_at(0), pat.span)
};
ctor = Single;
fields = Fields::singleton(cx, pat);
@@ -1343,7 +1344,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
ty
});
let mut wilds: SmallVec<[_; 2]> =
- tys.map(DeconstructedPat::wildcard).collect();
+ tys.map(|ty| DeconstructedPat::wildcard(ty, pat.span)).collect();
for pat in subpatterns {
if let Some(i) = field_id_to_id[pat.field.index()] {
wilds[i] = mkpat(&pat.pattern);
@@ -1438,7 +1439,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
ty::Tuple(..) => PatKind::Leaf {
subpatterns: subpatterns
.enumerate()
- .map(|(i, pattern)| FieldPat { field: Field::new(i), pattern })
+ .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern })
.collect(),
},
ty::Adt(adt_def, _) if adt_def.is_box() => {
@@ -1566,8 +1567,10 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
};
let prefix = &self.fields.fields[..prefix];
let suffix = &self.fields.fields[self_slice.arity() - suffix..];
- let wildcard: &_ =
- pcx.cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
+ let wildcard: &_ = pcx
+ .cx
+ .pattern_arena
+ .alloc(DeconstructedPat::wildcard(inner_ty, pcx.span));
let extra_wildcards = other_slice.arity() - self_slice.arity();
let extra_wildcards = (0..extra_wildcards).map(|_| wildcard);
prefix.iter().chain(extra_wildcards).chain(suffix).collect()
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 41306dd80..70d015a39 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -21,29 +21,20 @@ use rustc_middle::mir::interpret::{
ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar,
};
use rustc_middle::mir::{self, UserTypeProjection};
-use rustc_middle::mir::{BorrowKind, Field, Mutability};
+use rustc_middle::mir::{BorrowKind, Mutability};
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
use rustc_middle::ty::subst::{GenericArg, SubstsRef};
use rustc_middle::ty::CanonicalUserTypeAnnotation;
-use rustc_middle::ty::{self, AdtDef, ConstKind, DefIdTree, Region, Ty, TyCtxt, UserType};
+use rustc_middle::ty::{self, AdtDef, ConstKind, Region, Ty, TyCtxt, UserType};
use rustc_span::{Span, Symbol};
+use rustc_target::abi::FieldIdx;
use std::cmp::Ordering;
-#[derive(Clone, Debug)]
-enum PatternError {
- AssocConstInPattern(Span),
- ConstParamInPattern(Span),
- StaticInPattern(Span),
- NonConstPath(Span),
-}
-
struct PatCtxt<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
- errors: Vec<PatternError>,
- include_lint_checks: bool,
}
pub(super) fn pat_from_hir<'a, 'tcx>(
@@ -52,30 +43,13 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
typeck_results: &'a ty::TypeckResults<'tcx>,
pat: &'tcx hir::Pat<'tcx>,
) -> Box<Pat<'tcx>> {
- let mut pcx = PatCtxt::new(tcx, param_env, typeck_results);
+ let mut pcx = PatCtxt { tcx, param_env, typeck_results };
let result = pcx.lower_pattern(pat);
- if !pcx.errors.is_empty() {
- let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
- tcx.sess.delay_span_bug(pat.span, &msg);
- }
debug!("pat_from_hir({:?}) = {:?}", pat, result);
result
}
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
- fn new(
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- typeck_results: &'a ty::TypeckResults<'tcx>,
- ) -> Self {
- PatCtxt { tcx, param_env, typeck_results, errors: vec![], include_lint_checks: false }
- }
-
- fn include_lint_checks(&mut self) -> &mut Self {
- self.include_lint_checks = true;
- self
- }
-
fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
// When implicit dereferences have been inserted in this pattern, the unadjusted lowered
// pattern has the type that results *after* dereferencing. For example, in this code:
@@ -356,7 +330,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let subpatterns = fields
.iter()
.map(|field| FieldPat {
- field: Field::new(self.typeck_results.field_index(field.hir_id)),
+ field: self.typeck_results.field_index(field.hir_id),
pattern: self.lower_pattern(&field.pat),
})
.collect();
@@ -379,7 +353,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
pats.iter()
.enumerate_and_adjust(expected_len, gap_pos)
.map(|(i, subpattern)| FieldPat {
- field: Field::new(i),
+ field: FieldIdx::new(i),
pattern: self.lower_pattern(subpattern),
})
.collect()
@@ -472,12 +446,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
| Res::SelfTyAlias { .. }
| Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
_ => {
- let pattern_error = match res {
- Res::Def(DefKind::ConstParam, _) => PatternError::ConstParamInPattern(span),
- Res::Def(DefKind::Static(_), _) => PatternError::StaticInPattern(span),
- _ => PatternError::NonConstPath(span),
+ match res {
+ Res::Def(DefKind::ConstParam, _) => {
+ self.tcx.sess.emit_err(ConstParamInPattern { span })
+ }
+ Res::Def(DefKind::Static(_), _) => {
+ self.tcx.sess.emit_err(StaticInPattern { span })
+ }
+ _ => self.tcx.sess.emit_err(NonConstPath { span }),
};
- self.errors.push(pattern_error);
PatKind::Wild
}
};
@@ -530,7 +507,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// It should be assoc consts if there's no error but we cannot resolve it.
debug_assert!(is_associated_const);
- self.errors.push(PatternError::AssocConstInPattern(span));
+ self.tcx.sess.emit_err(AssocConstInPattern { span });
return pat_from_kind(PatKind::Wild);
}
@@ -608,7 +585,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
match value {
mir::ConstantKind::Ty(c) => match c.kind() {
ConstKind::Param(_) => {
- self.errors.push(PatternError::ConstParamInPattern(span));
+ self.tcx.sess.emit_err(ConstParamInPattern { span });
return PatKind::Wild;
}
ConstKind::Error(_) => {
@@ -723,7 +700,7 @@ macro_rules! ClonePatternFoldableImpls {
}
ClonePatternFoldableImpls! { <'tcx>
- Span, Field, Mutability, Symbol, LocalVarId, usize,
+ Span, FieldIdx, Mutability, Symbol, LocalVarId, usize,
Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>,
SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
UserTypeProjection, CanonicalUserTypeAnnotation<'tcx>
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index be66d0d47..d8f66a175 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -318,6 +318,8 @@ pub(crate) struct MatchCheckCtxt<'p, 'tcx> {
pub(crate) module: DefId,
pub(crate) param_env: ty::ParamEnv<'tcx>,
pub(crate) pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
+ /// Only produce `NON_EXHAUSTIVE_OMITTED_PATTERNS` lint on refutable patterns.
+ pub(crate) refutable: bool,
}
impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
@@ -603,7 +605,7 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
let new_patterns = if pcx.is_non_exhaustive {
// Here we don't want the user to try to list all variants, we want them to add
// a wildcard, so we only suggest that.
- vec![DeconstructedPat::wildcard(pcx.ty)]
+ vec![DeconstructedPat::wildcard(pcx.ty, pcx.span)]
} else {
let mut split_wildcard = SplitWildcard::new(pcx);
split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
@@ -630,7 +632,7 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
.collect();
if hide_variant_show_wild {
- new.push(DeconstructedPat::wildcard(pcx.ty));
+ new.push(DeconstructedPat::wildcard(pcx.ty, pcx.span));
}
new
@@ -733,7 +735,7 @@ impl<'p, 'tcx> Witness<'p, 'tcx> {
let arity = ctor.arity(pcx);
let pats = self.0.drain((len - arity)..).rev();
let fields = Fields::from_iter(pcx.cx, pats);
- DeconstructedPat::new(ctor.clone(), fields, pcx.ty, DUMMY_SP)
+ DeconstructedPat::new(ctor.clone(), fields, pcx.ty, pcx.span)
};
self.0.push(pat);
@@ -764,13 +766,13 @@ impl<'p, 'tcx> Witness<'p, 'tcx> {
/// `is_under_guard` is used to inform if the pattern has a guard. If it
/// has one it must not be inserted into the matrix. This shouldn't be
/// relied on for soundness.
-#[instrument(level = "debug", skip(cx, matrix, hir_id), ret)]
+#[instrument(level = "debug", skip(cx, matrix, lint_root), ret)]
fn is_useful<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
matrix: &Matrix<'p, 'tcx>,
v: &PatStack<'p, 'tcx>,
witness_preference: ArmType,
- hir_id: HirId,
+ lint_root: HirId,
is_under_guard: bool,
is_top_level: bool,
) -> Usefulness<'p, 'tcx> {
@@ -803,7 +805,7 @@ fn is_useful<'p, 'tcx>(
for v in v.expand_or_pat() {
debug!(?v);
let usefulness = ensure_sufficient_stack(|| {
- is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)
+ is_useful(cx, &matrix, &v, witness_preference, lint_root, is_under_guard, false)
});
debug!(?usefulness);
ret.extend(usefulness);
@@ -836,7 +838,7 @@ fn is_useful<'p, 'tcx>(
pcx,
matrix.heads(),
matrix.column_count().unwrap_or(0),
- hir_id,
+ lint_root,
)
}
// We split the head constructor of `v`.
@@ -851,7 +853,15 @@ fn is_useful<'p, 'tcx>(
let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
let v = v.pop_head_constructor(pcx, &ctor);
let usefulness = ensure_sufficient_stack(|| {
- is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false)
+ is_useful(
+ cx,
+ &spec_matrix,
+ &v,
+ witness_preference,
+ lint_root,
+ is_under_guard,
+ false,
+ )
});
let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor);
@@ -859,6 +869,8 @@ fn is_useful<'p, 'tcx>(
// that has the potential to trigger the `non_exhaustive_omitted_patterns` lint.
// To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors`
if is_non_exhaustive_and_wild
+ // Only emit a lint on refutable patterns.
+ && cx.refutable
// We check that the match has a wildcard pattern and that wildcard is useful,
// meaning there are variants that are covered by the wildcard. Without the check
// for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}`
@@ -893,7 +905,7 @@ fn is_useful<'p, 'tcx>(
// NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
cx.tcx.emit_spanned_lint(
NON_EXHAUSTIVE_OMITTED_PATTERNS,
- hir_id,
+ lint_root,
pcx.span,
NonExhaustiveOmittedPattern {
scrut_ty: pcx.ty,
@@ -951,7 +963,7 @@ pub(crate) struct UsefulnessReport<'p, 'tcx> {
pub(crate) fn compute_match_usefulness<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
arms: &[MatchArm<'p, 'tcx>],
- scrut_hir_id: HirId,
+ lint_root: HirId,
scrut_ty: Ty<'tcx>,
) -> UsefulnessReport<'p, 'tcx> {
let mut matrix = Matrix::empty();
@@ -974,9 +986,9 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
})
.collect();
- let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty));
+ let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP));
let v = PatStack::from_pattern(wild_pattern);
- let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, scrut_hir_id, false, true);
+ let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, lint_root, false, true);
let non_exhaustiveness_witnesses = match usefulness {
WithWitnesses(pats) => pats.into_iter().map(|w| w.single_pattern()).collect(),
NoWitnesses { .. } => bug!(),
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 8028227aa..ed61d6ee7 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -151,6 +151,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
initializer,
else_block,
lint_level,
+ span,
} => {
print_indented!(self, "kind: Let {", depth_lvl + 1);
print_indented!(
@@ -181,6 +182,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
}
print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 2);
+ print_indented!(self, format!("span: {:?}", span), depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1);
}
}