Fix inline const pattern unsafety checking in THIR
THIR unsafety checking was getting a cycle of function unsafety checking -> building THIR for the function -> evaluating pattern inline constants in the function -> building MIR for the inline constant -> checking unsafety of functions (so that THIR can be stolen) This is fixed by not stealing THIR when generating MIR but instead when unsafety checking. This leaves an issue with pattern inline constants not being unsafety checked because they are evaluated away when generating THIR. To fix that we now represent inline constants in THIR patterns and visit them in THIR unsafety checking.
This commit is contained in:
parent
e7bdc5f9f8
commit
5cc83fd4a5
24 changed files with 239 additions and 50 deletions
|
@ -775,12 +775,16 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
|
||||||
rustc_hir_analysis::check_crate(tcx)?;
|
rustc_hir_analysis::check_crate(tcx)?;
|
||||||
|
|
||||||
sess.time("MIR_borrow_checking", || {
|
sess.time("MIR_borrow_checking", || {
|
||||||
tcx.hir().par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id));
|
tcx.hir().par_body_owners(|def_id| {
|
||||||
|
// Run THIR unsafety check because it's responsible for stealing
|
||||||
|
// and deallocating THIR when enabled.
|
||||||
|
tcx.ensure().thir_check_unsafety(def_id);
|
||||||
|
tcx.ensure().mir_borrowck(def_id)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
sess.time("MIR_effect_checking", || {
|
sess.time("MIR_effect_checking", || {
|
||||||
for def_id in tcx.hir().body_owners() {
|
for def_id in tcx.hir().body_owners() {
|
||||||
tcx.ensure().thir_check_unsafety(def_id);
|
|
||||||
if !tcx.sess.opts.unstable_opts.thir_unsafeck {
|
if !tcx.sess.opts.unstable_opts.thir_unsafeck {
|
||||||
rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
|
rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -636,7 +636,8 @@ impl<'tcx> Pat<'tcx> {
|
||||||
Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {}
|
Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {}
|
||||||
AscribeUserType { subpattern, .. }
|
AscribeUserType { subpattern, .. }
|
||||||
| Binding { subpattern: Some(subpattern), .. }
|
| Binding { subpattern: Some(subpattern), .. }
|
||||||
| Deref { subpattern } => subpattern.walk_(it),
|
| Deref { subpattern }
|
||||||
|
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
|
||||||
Leaf { subpatterns } | Variant { subpatterns, .. } => {
|
Leaf { subpatterns } | Variant { subpatterns, .. } => {
|
||||||
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
|
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
|
||||||
}
|
}
|
||||||
|
@ -764,6 +765,11 @@ pub enum PatKind<'tcx> {
|
||||||
value: mir::Const<'tcx>,
|
value: mir::Const<'tcx>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
InlineConstant {
|
||||||
|
value: mir::UnevaluatedConst<'tcx>,
|
||||||
|
subpattern: Box<Pat<'tcx>>,
|
||||||
|
},
|
||||||
|
|
||||||
Range(Box<PatRange<'tcx>>),
|
Range(Box<PatRange<'tcx>>),
|
||||||
|
|
||||||
/// Matches against a slice, checking the length and extracting elements.
|
/// Matches against a slice, checking the length and extracting elements.
|
||||||
|
@ -924,6 +930,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
|
||||||
write!(f, "{subpattern}")
|
write!(f, "{subpattern}")
|
||||||
}
|
}
|
||||||
PatKind::Constant { value } => write!(f, "{value}"),
|
PatKind::Constant { value } => write!(f, "{value}"),
|
||||||
|
PatKind::InlineConstant { value: _, ref subpattern } => {
|
||||||
|
write!(f, "{} (from inline const)", subpattern)
|
||||||
|
}
|
||||||
PatKind::Range(box PatRange { lo, hi, end }) => {
|
PatKind::Range(box PatRange { lo, hi, end }) => {
|
||||||
write!(f, "{lo}")?;
|
write!(f, "{lo}")?;
|
||||||
write!(f, "{end}")?;
|
write!(f, "{end}")?;
|
||||||
|
|
|
@ -233,16 +233,17 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Constant { value: _ } => {}
|
Constant { value: _ } => {}
|
||||||
|
InlineConstant { value: _, subpattern } => visitor.visit_pat(subpattern),
|
||||||
Range(_) => {}
|
Range(_) => {}
|
||||||
Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
|
Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
|
||||||
for subpattern in prefix.iter() {
|
for subpattern in prefix.iter() {
|
||||||
visitor.visit_pat(&subpattern);
|
visitor.visit_pat(subpattern);
|
||||||
}
|
}
|
||||||
if let Some(pat) = slice {
|
if let Some(pat) = slice {
|
||||||
visitor.visit_pat(&pat);
|
visitor.visit_pat(pat);
|
||||||
}
|
}
|
||||||
for subpattern in suffix.iter() {
|
for subpattern in suffix.iter() {
|
||||||
visitor.visit_pat(&subpattern);
|
visitor.visit_pat(subpattern);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Or { pats } => {
|
Or { pats } => {
|
||||||
|
|
|
@ -847,6 +847,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
|
self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PatKind::InlineConstant { ref subpattern, .. } => {
|
||||||
|
self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f)
|
||||||
|
}
|
||||||
|
|
||||||
PatKind::Leaf { ref subpatterns } => {
|
PatKind::Leaf { ref subpatterns } => {
|
||||||
for subpattern in subpatterns {
|
for subpattern in subpatterns {
|
||||||
let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);
|
let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);
|
||||||
|
|
|
@ -204,6 +204,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
Err(match_pair)
|
Err(match_pair)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PatKind::InlineConstant { subpattern: ref pattern, value: _ } => {
|
||||||
|
candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
PatKind::Range(box PatRange { lo, hi, end }) => {
|
PatKind::Range(box PatRange { lo, hi, end }) => {
|
||||||
let (range, bias) = match *lo.ty().kind() {
|
let (range, bias) = match *lo.ty().kind() {
|
||||||
ty::Char => {
|
ty::Char => {
|
||||||
|
@ -229,11 +235,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// correct the comparison. This is achieved by XORing with a bias (see
|
// correct the comparison. This is achieved by XORing with a bias (see
|
||||||
// pattern/_match.rs for another pertinent example of this pattern).
|
// pattern/_match.rs for another pertinent example of this pattern).
|
||||||
//
|
//
|
||||||
// Also, for performance, it's important to only do the second `try_to_bits` if
|
// Also, for performance, it's important to only do the second
|
||||||
// necessary.
|
// `try_eval_scalar_int` if necessary.
|
||||||
let lo = lo.try_to_bits(sz).unwrap() ^ bias;
|
let lo = lo
|
||||||
|
.try_eval_scalar_int(self.tcx, self.param_env)
|
||||||
|
.unwrap()
|
||||||
|
.to_bits(sz)
|
||||||
|
.unwrap()
|
||||||
|
^ bias;
|
||||||
if lo <= min {
|
if lo <= min {
|
||||||
let hi = hi.try_to_bits(sz).unwrap() ^ bias;
|
let hi = hi
|
||||||
|
.try_eval_scalar_int(self.tcx, self.param_env)
|
||||||
|
.unwrap()
|
||||||
|
.to_bits(sz)
|
||||||
|
.unwrap()
|
||||||
|
^ bias;
|
||||||
if hi > max || hi == max && end == RangeEnd::Included {
|
if hi > max || hi == max && end == RangeEnd::Included {
|
||||||
// Irrefutable pattern match.
|
// Irrefutable pattern match.
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
|
@ -73,6 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
PatKind::Or { .. } => bug!("or-patterns should have already been handled"),
|
PatKind::Or { .. } => bug!("or-patterns should have already been handled"),
|
||||||
|
|
||||||
PatKind::AscribeUserType { .. }
|
PatKind::AscribeUserType { .. }
|
||||||
|
| PatKind::InlineConstant { .. }
|
||||||
| PatKind::Array { .. }
|
| PatKind::Array { .. }
|
||||||
| PatKind::Wild
|
| PatKind::Wild
|
||||||
| PatKind::Binding { .. }
|
| PatKind::Binding { .. }
|
||||||
|
@ -111,6 +112,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
| PatKind::Or { .. }
|
| PatKind::Or { .. }
|
||||||
| PatKind::Binding { .. }
|
| PatKind::Binding { .. }
|
||||||
| PatKind::AscribeUserType { .. }
|
| PatKind::AscribeUserType { .. }
|
||||||
|
| PatKind::InlineConstant { .. }
|
||||||
| PatKind::Leaf { .. }
|
| PatKind::Leaf { .. }
|
||||||
| PatKind::Deref { .. }
|
| PatKind::Deref { .. }
|
||||||
| PatKind::Error(_) => {
|
| PatKind::Error(_) => {
|
||||||
|
|
|
@ -53,10 +53,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct the MIR for a given `DefId`.
|
/// Construct the MIR for a given `DefId`.
|
||||||
fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
|
fn mir_build<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
|
||||||
// Ensure unsafeck and abstract const building is ran before we steal the THIR.
|
|
||||||
tcx.ensure_with_value()
|
|
||||||
.thir_check_unsafety(tcx.typeck_root_def_id(def.to_def_id()).expect_local());
|
|
||||||
tcx.ensure_with_value().thir_abstract_const(def);
|
tcx.ensure_with_value().thir_abstract_const(def);
|
||||||
if let Err(e) = tcx.check_match(def) {
|
if let Err(e) = tcx.check_match(def) {
|
||||||
return construct_error(tcx, def, e);
|
return construct_error(tcx, def, e);
|
||||||
|
@ -65,9 +62,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
|
||||||
let body = match tcx.thir_body(def) {
|
let body = match tcx.thir_body(def) {
|
||||||
Err(error_reported) => construct_error(tcx, def, error_reported),
|
Err(error_reported) => construct_error(tcx, def, error_reported),
|
||||||
Ok((thir, expr)) => {
|
Ok((thir, expr)) => {
|
||||||
// We ran all queries that depended on THIR at the beginning
|
let build_mir = |thir: &Thir<'tcx>| match thir.body_type {
|
||||||
// of `mir_build`, so now we can steal it
|
thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, thir, expr, fn_sig),
|
||||||
let thir = thir.steal();
|
thir::BodyTy::Const(ty) => construct_const(tcx, def, thir, expr, ty),
|
||||||
|
};
|
||||||
|
|
||||||
tcx.ensure().check_match(def);
|
tcx.ensure().check_match(def);
|
||||||
// this must run before MIR dump, because
|
// this must run before MIR dump, because
|
||||||
|
@ -76,9 +74,16 @@ fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
|
||||||
// maybe move the check to a MIR pass?
|
// maybe move the check to a MIR pass?
|
||||||
tcx.ensure().check_liveness(def);
|
tcx.ensure().check_liveness(def);
|
||||||
|
|
||||||
match thir.body_type {
|
if tcx.sess.opts.unstable_opts.thir_unsafeck {
|
||||||
thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, &thir, expr, fn_sig),
|
// Don't steal here if THIR unsafeck is being used. Instead
|
||||||
thir::BodyTy::Const(ty) => construct_const(tcx, def, &thir, expr, ty),
|
// steal in unsafeck. This is so that pattern inline constants
|
||||||
|
// can be evaluated as part of building the THIR of the parent
|
||||||
|
// function without a cycle.
|
||||||
|
build_mir(&thir.borrow())
|
||||||
|
} else {
|
||||||
|
// We ran all queries that depended on THIR at the beginning
|
||||||
|
// of `mir_build`, so now we can steal it
|
||||||
|
build_mir(&thir.steal())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::errors::*;
|
||||||
use rustc_middle::thir::visit::{self, Visitor};
|
use rustc_middle::thir::visit::{self, Visitor};
|
||||||
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_middle::mir::BorrowKind;
|
use rustc_middle::mir::{BorrowKind, Const};
|
||||||
use rustc_middle::thir::*;
|
use rustc_middle::thir::*;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
|
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
|
||||||
|
@ -124,7 +124,8 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
||||||
/// Handle closures/generators/inline-consts, which is unsafecked with their parent body.
|
/// Handle closures/generators/inline-consts, which is unsafecked with their parent body.
|
||||||
fn visit_inner_body(&mut self, def: LocalDefId) {
|
fn visit_inner_body(&mut self, def: LocalDefId) {
|
||||||
if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
|
if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
|
||||||
let inner_thir = &inner_thir.borrow();
|
let _ = self.tcx.ensure_with_value().mir_built(def);
|
||||||
|
let inner_thir = &inner_thir.steal();
|
||||||
let hir_context = self.tcx.hir().local_def_id_to_hir_id(def);
|
let hir_context = self.tcx.hir().local_def_id_to_hir_id(def);
|
||||||
let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self };
|
let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self };
|
||||||
inner_visitor.visit_expr(&inner_thir[expr]);
|
inner_visitor.visit_expr(&inner_thir[expr]);
|
||||||
|
@ -224,6 +225,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||||
PatKind::Wild |
|
PatKind::Wild |
|
||||||
// these just wrap other patterns
|
// these just wrap other patterns
|
||||||
PatKind::Or { .. } |
|
PatKind::Or { .. } |
|
||||||
|
PatKind::InlineConstant { .. } |
|
||||||
PatKind::AscribeUserType { .. } |
|
PatKind::AscribeUserType { .. } |
|
||||||
PatKind::Error(_) => {}
|
PatKind::Error(_) => {}
|
||||||
}
|
}
|
||||||
|
@ -277,6 +279,24 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||||
visit::walk_pat(self, pat);
|
visit::walk_pat(self, pat);
|
||||||
self.inside_adt = old_inside_adt;
|
self.inside_adt = old_inside_adt;
|
||||||
}
|
}
|
||||||
|
PatKind::Range(range) => {
|
||||||
|
if let Const::Unevaluated(c, _) = range.lo {
|
||||||
|
if let hir::def::DefKind::InlineConst = self.tcx.def_kind(c.def) {
|
||||||
|
let def_id = c.def.expect_local();
|
||||||
|
self.visit_inner_body(def_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Const::Unevaluated(c, _) = range.hi {
|
||||||
|
if let hir::def::DefKind::InlineConst = self.tcx.def_kind(c.def) {
|
||||||
|
let def_id = c.def.expect_local();
|
||||||
|
self.visit_inner_body(def_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PatKind::InlineConstant { value, .. } => {
|
||||||
|
let def_id = value.def.expect_local();
|
||||||
|
self.visit_inner_body(def_id);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
visit::walk_pat(self, pat);
|
visit::walk_pat(self, pat);
|
||||||
}
|
}
|
||||||
|
@ -788,7 +808,8 @@ pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let Ok((thir, expr)) = tcx.thir_body(def) else { return };
|
let Ok((thir, expr)) = tcx.thir_body(def) else { return };
|
||||||
let thir = &thir.borrow();
|
let _ = tcx.ensure_with_value().mir_built(def);
|
||||||
|
let thir = &thir.steal();
|
||||||
// If `thir` is empty, a type error occurred, skip this body.
|
// If `thir` is empty, a type error occurred, skip this body.
|
||||||
if thir.exprs.is_empty() {
|
if thir.exprs.is_empty() {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1356,7 +1356,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
|
||||||
let ctor;
|
let ctor;
|
||||||
let fields;
|
let fields;
|
||||||
match &pat.kind {
|
match &pat.kind {
|
||||||
PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern),
|
PatKind::AscribeUserType { subpattern, .. }
|
||||||
|
| PatKind::InlineConstant { subpattern, .. } => return mkpat(subpattern),
|
||||||
PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat),
|
PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat),
|
||||||
PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
|
PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
|
||||||
ctor = Wildcard;
|
ctor = Wildcard;
|
||||||
|
|
|
@ -93,6 +93,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
None => Ok((None, None)),
|
None => Ok((None, None)),
|
||||||
Some(expr) => {
|
Some(expr) => {
|
||||||
let (kind, ascr) = match self.lower_lit(expr) {
|
let (kind, ascr) = match self.lower_lit(expr) {
|
||||||
|
PatKind::InlineConstant { subpattern, value } => (
|
||||||
|
PatKind::Constant { value: Const::Unevaluated(value, subpattern.ty) },
|
||||||
|
None,
|
||||||
|
),
|
||||||
PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
|
PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
|
||||||
(kind, Some(ascription))
|
(kind, Some(ascription))
|
||||||
}
|
}
|
||||||
|
@ -633,13 +637,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
if let Ok(Some(valtree)) =
|
if let Ok(Some(valtree)) =
|
||||||
self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
|
self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
|
||||||
{
|
{
|
||||||
self.const_to_pat(
|
let subpattern = self.const_to_pat(
|
||||||
Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
|
Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
|
||||||
id,
|
id,
|
||||||
span,
|
span,
|
||||||
None,
|
None,
|
||||||
)
|
);
|
||||||
.kind
|
PatKind::InlineConstant { subpattern, value: uneval }
|
||||||
} else {
|
} else {
|
||||||
// If that fails, convert it to an opaque constant pattern.
|
// If that fails, convert it to an opaque constant pattern.
|
||||||
match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
|
match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
|
||||||
|
@ -822,6 +826,9 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
|
||||||
PatKind::Deref { subpattern: subpattern.fold_with(folder) }
|
PatKind::Deref { subpattern: subpattern.fold_with(folder) }
|
||||||
}
|
}
|
||||||
PatKind::Constant { value } => PatKind::Constant { value },
|
PatKind::Constant { value } => PatKind::Constant { value },
|
||||||
|
PatKind::InlineConstant { value, subpattern: ref pattern } => {
|
||||||
|
PatKind::InlineConstant { value, subpattern: pattern.fold_with(folder) }
|
||||||
|
}
|
||||||
PatKind::Range(ref range) => PatKind::Range(range.clone()),
|
PatKind::Range(ref range) => PatKind::Range(range.clone()),
|
||||||
PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice {
|
PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice {
|
||||||
prefix: prefix.fold_with(folder),
|
prefix: prefix.fold_with(folder),
|
||||||
|
|
|
@ -701,6 +701,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
||||||
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
|
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
|
||||||
print_indented!(self, "}", depth_lvl + 1);
|
print_indented!(self, "}", depth_lvl + 1);
|
||||||
}
|
}
|
||||||
|
PatKind::InlineConstant { value, subpattern } => {
|
||||||
|
print_indented!(self, "InlineConstant {", depth_lvl + 1);
|
||||||
|
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
|
||||||
|
print_indented!(self, "subpattern: ", depth_lvl + 2);
|
||||||
|
self.print_pat(subpattern, depth_lvl + 2);
|
||||||
|
print_indented!(self, "}", depth_lvl + 1);
|
||||||
|
}
|
||||||
PatKind::Range(pat_range) => {
|
PatKind::Range(pat_range) => {
|
||||||
print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1);
|
print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ LL | S::f();
|
||||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
|
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
|
||||||
--> $DIR/async-unsafe-fn-call-in-safe.rs:24:5
|
--> $DIR/async-unsafe-fn-call-in-safe.rs:26:5
|
||||||
|
|
|
|
||||||
LL | f();
|
LL | f();
|
||||||
| ^^^ call to unsafe function
|
| ^^^ call to unsafe function
|
||||||
|
|
|
@ -20,6 +20,10 @@ async fn g() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
S::f(); //[mir]~ ERROR call to unsafe function is unsafe
|
S::f();
|
||||||
f(); //[mir]~ ERROR call to unsafe function is unsafe
|
//[mir]~^ ERROR call to unsafe function is unsafe
|
||||||
|
//[thir]~^^ ERROR call to unsafe function `S::f` is unsafe
|
||||||
|
f();
|
||||||
|
//[mir]~^ ERROR call to unsafe function is unsafe
|
||||||
|
//[thir]~^^ ERROR call to unsafe function `f` is unsafe
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,22 @@ LL | f();
|
||||||
|
|
|
|
||||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error[E0133]: call to unsafe function `S::f` is unsafe and requires unsafe function or block
|
||||||
|
--> $DIR/async-unsafe-fn-call-in-safe.rs:23:5
|
||||||
|
|
|
||||||
|
LL | S::f();
|
||||||
|
| ^^^^^^ call to unsafe function
|
||||||
|
|
|
||||||
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
|
error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block
|
||||||
|
--> $DIR/async-unsafe-fn-call-in-safe.rs:26:5
|
||||||
|
|
|
||||||
|
LL | f();
|
||||||
|
| ^^^ call to unsafe function
|
||||||
|
|
|
||||||
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0133`.
|
For more information about this error, try `rustc --explain E0133`.
|
||||||
|
|
|
@ -11,4 +11,5 @@ fn main() {
|
||||||
//[thir]~^^ call to unsafe function `foo` is unsafe and requires unsafe function or block
|
//[thir]~^^ call to unsafe function `foo` is unsafe and requires unsafe function or block
|
||||||
foo();
|
foo();
|
||||||
//[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
|
//[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
|
||||||
|
//[thir]~^^ ERROR call to unsafe function `foo` is unsafe and requires unsafe function or block
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
|
||||||
|
--> $DIR/const-extern-fn-requires-unsafe.rs:12:5
|
||||||
|
|
|
||||||
|
LL | foo();
|
||||||
|
| ^^^^^ call to unsafe function
|
||||||
|
|
|
||||||
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
|
error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
|
||||||
--> $DIR/const-extern-fn-requires-unsafe.rs:9:17
|
--> $DIR/const-extern-fn-requires-unsafe.rs:9:17
|
||||||
|
|
|
|
||||||
|
@ -6,6 +14,6 @@ LL | let a: [u8; foo()];
|
||||||
|
|
|
|
||||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0133`.
|
For more information about this error, try `rustc --explain E0133`.
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
// ignore-test This is currently broken
|
|
||||||
// revisions: mir thir
|
// revisions: mir thir
|
||||||
|
// [mir]ignore-test This is currently broken
|
||||||
// [thir]compile-flags: -Z thir-unsafeck
|
// [thir]compile-flags: -Z thir-unsafeck
|
||||||
|
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
#![feature(inline_const_pat)]
|
#![feature(inline_const_pat)]
|
||||||
|
|
||||||
const unsafe fn require_unsafe() -> usize { 1 }
|
const unsafe fn require_unsafe() -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match () {
|
match () {
|
||||||
|
@ -14,4 +16,12 @@ fn main() {
|
||||||
//~^ ERROR [E0133]
|
//~^ ERROR [E0133]
|
||||||
} => (),
|
} => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match 1 {
|
||||||
|
const {
|
||||||
|
require_unsafe()
|
||||||
|
//~^ ERROR [E0133]
|
||||||
|
}..=4 => (),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
19
tests/ui/inline-const/pat-unsafe-err.thir.stderr
Normal file
19
tests/ui/inline-const/pat-unsafe-err.thir.stderr
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
|
||||||
|
--> $DIR/pat-unsafe-err.rs:15:13
|
||||||
|
|
|
||||||
|
LL | require_unsafe();
|
||||||
|
| ^^^^^^^^^^^^^^^^ call to unsafe function
|
||||||
|
|
|
||||||
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
|
error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
|
||||||
|
--> $DIR/pat-unsafe-err.rs:22:13
|
||||||
|
|
|
||||||
|
LL | require_unsafe()
|
||||||
|
| ^^^^^^^^^^^^^^^^ call to unsafe function
|
||||||
|
|
|
||||||
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0133`.
|
|
@ -1,13 +1,15 @@
|
||||||
// ignore-test This is currently broken
|
|
||||||
// check-pass
|
// check-pass
|
||||||
// revisions: mir thir
|
// revisions: mir thir
|
||||||
|
// [mir]ignore-test This is currently broken
|
||||||
// [thir]compile-flags: -Z thir-unsafeck
|
// [thir]compile-flags: -Z thir-unsafeck
|
||||||
|
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
#![warn(unused_unsafe)]
|
#![warn(unused_unsafe)]
|
||||||
#![feature(inline_const_pat)]
|
#![feature(inline_const_pat)]
|
||||||
|
|
||||||
const unsafe fn require_unsafe() -> usize { 1 }
|
const unsafe fn require_unsafe() -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -18,5 +20,14 @@ fn main() {
|
||||||
//~^ WARNING unnecessary `unsafe` block
|
//~^ WARNING unnecessary `unsafe` block
|
||||||
} => (),
|
} => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match 1 {
|
||||||
|
const {
|
||||||
|
unsafe {}
|
||||||
|
//~^ WARNING unnecessary `unsafe` block
|
||||||
|
require_unsafe()
|
||||||
|
}..=4 => (),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
26
tests/ui/inline-const/pat-unsafe.thir.stderr
Normal file
26
tests/ui/inline-const/pat-unsafe.thir.stderr
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
warning: unnecessary `unsafe` block
|
||||||
|
--> $DIR/pat-unsafe.rs:19:17
|
||||||
|
|
|
||||||
|
LL | unsafe {
|
||||||
|
| ------ because it's nested under this `unsafe` block
|
||||||
|
...
|
||||||
|
LL | unsafe {}
|
||||||
|
| ^^^^^^ unnecessary `unsafe` block
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/pat-unsafe.rs:7:9
|
||||||
|
|
|
||||||
|
LL | #![warn(unused_unsafe)]
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
warning: unnecessary `unsafe` block
|
||||||
|
--> $DIR/pat-unsafe.rs:26:17
|
||||||
|
|
|
||||||
|
LL | unsafe {
|
||||||
|
| ------ because it's nested under this `unsafe` block
|
||||||
|
...
|
||||||
|
LL | unsafe {}
|
||||||
|
| ^^^^^^ unnecessary `unsafe` block
|
||||||
|
|
||||||
|
warning: 2 warnings emitted
|
||||||
|
|
14
tests/ui/pattern/non-structural-match-types.mir.stderr
Normal file
14
tests/ui/pattern/non-structural-match-types.mir.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error: `{closure@$DIR/non-structural-match-types.rs:12:17: 12:19}` cannot be used in patterns
|
||||||
|
--> $DIR/non-structural-match-types.rs:12:9
|
||||||
|
|
|
||||||
|
LL | const { || {} } => {}
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: `{async block@$DIR/non-structural-match-types.rs:15:17: 15:25}` cannot be used in patterns
|
||||||
|
--> $DIR/non-structural-match-types.rs:15:9
|
||||||
|
|
|
||||||
|
LL | const { async {} } => {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
// edition:2021
|
// edition:2021
|
||||||
|
// revisions: mir thir
|
||||||
|
// [thir]compile-flags: -Z thir-unsafeck
|
||||||
|
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
#![allow(unreachable_code)]
|
#![allow(unreachable_code)]
|
||||||
#![feature(const_async_blocks)]
|
#![feature(const_async_blocks)]
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
error: `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` cannot be used in patterns
|
|
||||||
--> $DIR/non-structural-match-types.rs:9:9
|
|
||||||
|
|
|
||||||
LL | const { || {} } => {}
|
|
||||||
| ^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: `{async block@$DIR/non-structural-match-types.rs:12:17: 12:25}` cannot be used in patterns
|
|
||||||
--> $DIR/non-structural-match-types.rs:12:9
|
|
||||||
|
|
|
||||||
LL | const { async {} } => {}
|
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
14
tests/ui/pattern/non-structural-match-types.thir.stderr
Normal file
14
tests/ui/pattern/non-structural-match-types.thir.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error: `{closure@$DIR/non-structural-match-types.rs:12:17: 12:19}` cannot be used in patterns
|
||||||
|
--> $DIR/non-structural-match-types.rs:12:9
|
||||||
|
|
|
||||||
|
LL | const { || {} } => {}
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: `{async block@$DIR/non-structural-match-types.rs:15:17: 15:25}` cannot be used in patterns
|
||||||
|
--> $DIR/non-structural-match-types.rs:15:9
|
||||||
|
|
|
||||||
|
LL | const { async {} } => {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue