mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Auto merge of #101143 - matthiaskrgr:rollup-g8y5k0g, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #94890 (Support parsing IP addresses from a byte string) - #96334 (socket `set_mark` addition.) - #99027 (Replace `Body::basic_blocks()` with field access) - #100437 (Improve const mismatch `FulfillmentError`) - #100843 (Migrate part of rustc_infer to session diagnostic) - #100897 (extra sanity check against consts pointing to mutable memory) - #100959 (translations: rename warn_ to warning) - #101111 (Use the declaration's SourceInfo for FnEntry retags, not the outermost) - #101116 ([rustdoc] Remove Attrs type alias) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
94b2b15e63
@ -3631,6 +3631,7 @@ dependencies = [
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"smallvec",
|
||||
|
@ -31,7 +31,7 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
|
||||
body,
|
||||
};
|
||||
|
||||
for (bb, data) in body.basic_blocks().iter_enumerated() {
|
||||
for (bb, data) in body.basic_blocks.iter_enumerated() {
|
||||
cg.visit_basic_block_data(bb, data);
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ struct OutOfScopePrecomputer<'a, 'tcx> {
|
||||
impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> {
|
||||
fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
|
||||
OutOfScopePrecomputer {
|
||||
visited: BitSet::new_empty(body.basic_blocks().len()),
|
||||
visited: BitSet::new_empty(body.basic_blocks.len()),
|
||||
visit_stack: vec![],
|
||||
body,
|
||||
regioncx,
|
||||
|
@ -459,7 +459,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
return outmost_back_edge;
|
||||
}
|
||||
|
||||
let block = &self.body.basic_blocks()[location.block];
|
||||
let block = &self.body.basic_blocks[location.block];
|
||||
|
||||
if location.statement_index < block.statements.len() {
|
||||
let successor = location.successor_within_block();
|
||||
@ -518,7 +518,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
if loop_head.dominates(from, &self.dominators) {
|
||||
let block = &self.body.basic_blocks()[from.block];
|
||||
let block = &self.body.basic_blocks[from.block];
|
||||
|
||||
if from.statement_index < block.statements.len() {
|
||||
let successor = from.successor_within_block();
|
||||
@ -568,7 +568,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
UseSpans::PatUse(span)
|
||||
| UseSpans::OtherUse(span)
|
||||
| UseSpans::FnSelfUse { var_span: span, .. } => {
|
||||
let block = &self.body.basic_blocks()[location.block];
|
||||
let block = &self.body.basic_blocks[location.block];
|
||||
|
||||
let kind = if let Some(&Statement {
|
||||
kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)),
|
||||
|
@ -88,7 +88,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if let Some(StatementKind::Assign(box (
|
||||
place,
|
||||
Rvalue::Use(Operand::Move(move_from)),
|
||||
))) = self.body.basic_blocks()[location.block]
|
||||
))) = self.body.basic_blocks[location.block]
|
||||
.statements
|
||||
.get(location.statement_index)
|
||||
.map(|stmt| &stmt.kind)
|
||||
|
@ -33,7 +33,7 @@ impl LocationTable {
|
||||
pub(crate) fn new(body: &Body<'_>) -> Self {
|
||||
let mut num_points = 0;
|
||||
let statements_before_block = body
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.iter()
|
||||
.map(|block_data| {
|
||||
let v = num_points;
|
||||
|
@ -25,7 +25,7 @@ impl RegionValueElements {
|
||||
pub(crate) fn new(body: &Body<'_>) -> Self {
|
||||
let mut num_points = 0;
|
||||
let statements_before_block: IndexVec<BasicBlock, usize> = body
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.iter()
|
||||
.map(|block_data| {
|
||||
let v = num_points;
|
||||
@ -37,7 +37,7 @@ impl RegionValueElements {
|
||||
debug!("RegionValueElements: num_points={:#?}", num_points);
|
||||
|
||||
let mut basic_blocks = IndexVec::with_capacity(num_points);
|
||||
for (bb, bb_data) in body.basic_blocks().iter_enumerated() {
|
||||
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
|
||||
basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
|
||||
}
|
||||
|
||||
|
@ -2633,7 +2633,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.check_local(&body, local, local_decl);
|
||||
}
|
||||
|
||||
for (block, block_data) in body.basic_blocks().iter_enumerated() {
|
||||
for (block, block_data) in body.basic_blocks.iter_enumerated() {
|
||||
let mut location = Location { block, statement_index: 0 };
|
||||
for stmt in &block_data.statements {
|
||||
if !stmt.source_info.span.is_dummy() {
|
||||
|
@ -26,7 +26,7 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, '_>) -> IndexVec<Local, SsaKind> {
|
||||
})
|
||||
.collect::<IndexVec<Local, SsaKind>>();
|
||||
|
||||
for bb in fx.mir.basic_blocks().iter() {
|
||||
for bb in fx.mir.basic_blocks.iter() {
|
||||
for stmt in bb.statements.iter() {
|
||||
match &stmt.kind {
|
||||
Assign(place_and_rval) => match &place_and_rval.1 {
|
||||
|
@ -73,7 +73,7 @@ pub(crate) fn codegen_fn<'tcx>(
|
||||
// Predefine blocks
|
||||
let start_block = bcx.create_block();
|
||||
let block_map: IndexVec<BasicBlock, Block> =
|
||||
(0..mir.basic_blocks().len()).map(|_| bcx.create_block()).collect();
|
||||
(0..mir.basic_blocks.len()).map(|_| bcx.create_block()).collect();
|
||||
|
||||
// Make FunctionCx
|
||||
let target_config = module.target_config();
|
||||
@ -271,7 +271,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||
}
|
||||
fx.tcx.sess.time("codegen prelude", || crate::abi::codegen_fn_prelude(fx, start_block));
|
||||
|
||||
for (bb, bb_data) in fx.mir.basic_blocks().iter_enumerated() {
|
||||
for (bb, bb_data) in fx.mir.basic_blocks.iter_enumerated() {
|
||||
let block = fx.get_block(bb);
|
||||
fx.bcx.switch_to_block(block);
|
||||
|
||||
|
@ -505,7 +505,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
||||
return None;
|
||||
}
|
||||
let mut computed_const_val = None;
|
||||
for bb_data in fx.mir.basic_blocks() {
|
||||
for bb_data in fx.mir.basic_blocks.iter() {
|
||||
for stmt in &bb_data.statements {
|
||||
match &stmt.kind {
|
||||
StatementKind::Assign(local_and_rvalue) if &local_and_rvalue.0 == place => {
|
||||
|
@ -266,7 +266,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
|
||||
result: &mut IndexVec<mir::BasicBlock, CleanupKind>,
|
||||
mir: &mir::Body<'tcx>,
|
||||
) {
|
||||
for (bb, data) in mir.basic_blocks().iter_enumerated() {
|
||||
for (bb, data) in mir.basic_blocks.iter_enumerated() {
|
||||
match data.terminator().kind {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::Resume
|
||||
@ -296,7 +296,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
|
||||
}
|
||||
|
||||
fn propagate<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>, mir: &mir::Body<'tcx>) {
|
||||
let mut funclet_succs = IndexVec::from_elem(None, mir.basic_blocks());
|
||||
let mut funclet_succs = IndexVec::from_elem(None, &mir.basic_blocks);
|
||||
|
||||
let mut set_successor = |funclet: mir::BasicBlock, succ| match funclet_succs[funclet] {
|
||||
ref mut s @ None => {
|
||||
@ -359,7 +359,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
|
||||
}
|
||||
}
|
||||
|
||||
let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, mir.basic_blocks());
|
||||
let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, &mir.basic_blocks);
|
||||
|
||||
discover_masters(&mut result, mir);
|
||||
propagate(&mut result, mir);
|
||||
|
@ -150,13 +150,13 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
let start_llbb = Bx::append_block(cx, llfn, "start");
|
||||
let mut bx = Bx::build(cx, start_llbb);
|
||||
|
||||
if mir.basic_blocks().iter().any(|bb| bb.is_cleanup) {
|
||||
if mir.basic_blocks.iter().any(|bb| bb.is_cleanup) {
|
||||
bx.set_personality_fn(cx.eh_personality());
|
||||
}
|
||||
|
||||
let cleanup_kinds = analyze::cleanup_kinds(&mir);
|
||||
let cached_llbbs: IndexVec<mir::BasicBlock, Option<Bx::BasicBlock>> = mir
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.indices()
|
||||
.map(|bb| if bb == mir::START_BLOCK { Some(start_llbb) } else { None })
|
||||
.collect();
|
||||
@ -172,8 +172,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
unreachable_block: None,
|
||||
double_unwind_guard: None,
|
||||
cleanup_kinds,
|
||||
landing_pads: IndexVec::from_elem(None, mir.basic_blocks()),
|
||||
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks().len()),
|
||||
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
|
||||
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
|
||||
locals: IndexVec::new(),
|
||||
debug_context,
|
||||
per_local_var_debug_info: None,
|
||||
|
@ -782,7 +782,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
assert_eq!(
|
||||
unwinding,
|
||||
match self.frame().loc {
|
||||
Ok(loc) => self.body().basic_blocks()[loc.block].is_cleanup,
|
||||
Ok(loc) => self.body().basic_blocks[loc.block].is_cleanup,
|
||||
Err(_) => true,
|
||||
}
|
||||
);
|
||||
|
@ -28,7 +28,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let mut source_info = *frame.body.source_info(loc);
|
||||
|
||||
// If this is a `Call` terminator, use the `fn_span` instead.
|
||||
let block = &frame.body.basic_blocks()[loc.block];
|
||||
let block = &frame.body.basic_blocks[loc.block];
|
||||
if loc.statement_index == block.statements.len() {
|
||||
debug!(
|
||||
"find_closest_untracked_caller_location: got terminator {:?} ({:?})",
|
||||
|
@ -53,7 +53,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
self.pop_stack_frame(/* unwinding */ true)?;
|
||||
return Ok(true);
|
||||
};
|
||||
let basic_block = &self.body().basic_blocks()[loc.block];
|
||||
let basic_block = &self.body().basic_blocks[loc.block];
|
||||
|
||||
if let Some(stmt) = basic_block.statements.get(loc.statement_index) {
|
||||
let old_frames = self.frame_idx();
|
||||
|
@ -8,6 +8,7 @@ use std::convert::TryFrom;
|
||||
use std::fmt::Write;
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::interpret::InterpError;
|
||||
@ -423,34 +424,51 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
// Proceed recursively even for ZST, no reason to skip them!
|
||||
// `!` is a ZST and we want to validate it.
|
||||
if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
|
||||
// Special handling for pointers to statics (irrespective of their type).
|
||||
// Let's see what kind of memory this points to.
|
||||
let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id);
|
||||
if let Some(GlobalAlloc::Static(did)) = alloc_kind {
|
||||
assert!(!self.ecx.tcx.is_thread_local_static(did));
|
||||
assert!(self.ecx.tcx.is_static(did));
|
||||
if matches!(
|
||||
self.ctfe_mode,
|
||||
Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. })
|
||||
) {
|
||||
// See const_eval::machine::MemoryExtra::can_access_statics for why
|
||||
// this check is so important.
|
||||
// This check is reachable when the const just referenced the static,
|
||||
// but never read it (so we never entered `before_access_global`).
|
||||
throw_validation_failure!(self.path,
|
||||
{ "a {} pointing to a static variable", kind }
|
||||
);
|
||||
match alloc_kind {
|
||||
Some(GlobalAlloc::Static(did)) => {
|
||||
// Special handling for pointers to statics (irrespective of their type).
|
||||
assert!(!self.ecx.tcx.is_thread_local_static(did));
|
||||
assert!(self.ecx.tcx.is_static(did));
|
||||
if matches!(
|
||||
self.ctfe_mode,
|
||||
Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. })
|
||||
) {
|
||||
// See const_eval::machine::MemoryExtra::can_access_statics for why
|
||||
// this check is so important.
|
||||
// This check is reachable when the const just referenced the static,
|
||||
// but never read it (so we never entered `before_access_global`).
|
||||
throw_validation_failure!(self.path,
|
||||
{ "a {} pointing to a static variable in a constant", kind }
|
||||
);
|
||||
}
|
||||
// We skip recursively checking other statics. These statics must be sound by
|
||||
// themselves, and the only way to get broken statics here is by using
|
||||
// unsafe code.
|
||||
// The reasons we don't check other statics is twofold. For one, in all
|
||||
// sound cases, the static was already validated on its own, and second, we
|
||||
// trigger cycle errors if we try to compute the value of the other static
|
||||
// and that static refers back to us.
|
||||
// We might miss const-invalid data,
|
||||
// but things are still sound otherwise (in particular re: consts
|
||||
// referring to statics).
|
||||
return Ok(());
|
||||
}
|
||||
// We skip checking other statics. These statics must be sound by
|
||||
// themselves, and the only way to get broken statics here is by using
|
||||
// unsafe code.
|
||||
// The reasons we don't check other statics is twofold. For one, in all
|
||||
// sound cases, the static was already validated on its own, and second, we
|
||||
// trigger cycle errors if we try to compute the value of the other static
|
||||
// and that static refers back to us.
|
||||
// We might miss const-invalid data,
|
||||
// but things are still sound otherwise (in particular re: consts
|
||||
// referring to statics).
|
||||
return Ok(());
|
||||
Some(GlobalAlloc::Memory(alloc)) => {
|
||||
if alloc.inner().mutability == Mutability::Mut
|
||||
&& matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. }))
|
||||
{
|
||||
// This should be unreachable, but if someone manages to copy a pointer
|
||||
// out of a `static`, then that pointer might point to mutable memory,
|
||||
// and we would catch that here.
|
||||
throw_validation_failure!(self.path,
|
||||
{ "a {} pointing to mutable memory in a constant", kind }
|
||||
);
|
||||
}
|
||||
}
|
||||
// Nothing to check for these.
|
||||
None | Some(GlobalAlloc::Function(..) | GlobalAlloc::VTable(..)) => {}
|
||||
}
|
||||
}
|
||||
let path = &self.path;
|
||||
@ -528,7 +546,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
}
|
||||
ty::Ref(_, ty, mutbl) => {
|
||||
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. }))
|
||||
&& *mutbl == hir::Mutability::Mut
|
||||
&& *mutbl == Mutability::Mut
|
||||
{
|
||||
// A mutable reference inside a const? That does not seem right (except if it is
|
||||
// a ZST).
|
||||
|
@ -135,7 +135,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
||||
// qualifs for the return type.
|
||||
let return_block = ccx
|
||||
.body
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.iter_enumerated()
|
||||
.find(|(_, block)| matches!(block.terminator().kind, TerminatorKind::Return))
|
||||
.map(|(bb, _)| bb);
|
||||
|
@ -710,7 +710,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) {
|
||||
let last = self.promoted.basic_blocks().last().unwrap();
|
||||
let last = self.promoted.basic_blocks.last().unwrap();
|
||||
let data = &mut self.promoted[last];
|
||||
data.statements.push(Statement {
|
||||
source_info: SourceInfo::outermost(span),
|
||||
@ -803,7 +803,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
self.visit_operand(arg, loc);
|
||||
}
|
||||
|
||||
let last = self.promoted.basic_blocks().last().unwrap();
|
||||
let last = self.promoted.basic_blocks.last().unwrap();
|
||||
let new_target = self.new_block();
|
||||
|
||||
*self.promoted[last].terminator_mut() = Terminator {
|
||||
@ -1041,7 +1041,7 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>(
|
||||
_ => {}
|
||||
}
|
||||
|
||||
for block in body.basic_blocks() {
|
||||
for block in body.basic_blocks.iter() {
|
||||
if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) =
|
||||
&block.terminator
|
||||
{
|
||||
|
@ -140,8 +140,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
if bb == START_BLOCK {
|
||||
self.fail(location, "start block must not have predecessors")
|
||||
}
|
||||
if let Some(bb) = self.body.basic_blocks().get(bb) {
|
||||
let src = self.body.basic_blocks().get(location.block).unwrap();
|
||||
if let Some(bb) = self.body.basic_blocks.get(bb) {
|
||||
let src = self.body.basic_blocks.get(location.block).unwrap();
|
||||
match (src.is_cleanup, bb.is_cleanup, edge_kind) {
|
||||
// Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges
|
||||
(false, false, EdgeKind::Normal)
|
||||
@ -881,13 +881,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
TerminatorKind::Resume | TerminatorKind::Abort => {
|
||||
let bb = location.block;
|
||||
if !self.body.basic_blocks()[bb].is_cleanup {
|
||||
if !self.body.basic_blocks[bb].is_cleanup {
|
||||
self.fail(location, "Cannot `Resume` or `Abort` from non-cleanup basic block")
|
||||
}
|
||||
}
|
||||
TerminatorKind::Return => {
|
||||
let bb = location.block;
|
||||
if self.body.basic_blocks()[bb].is_cleanup {
|
||||
if self.body.basic_blocks[bb].is_cleanup {
|
||||
self.fail(location, "Cannot `Return` from cleanup basic block")
|
||||
}
|
||||
}
|
||||
|
112
compiler/rustc_error_messages/locales/en-US/infer.ftl
Normal file
112
compiler/rustc_error_messages/locales/en-US/infer.ftl
Normal file
@ -0,0 +1,112 @@
|
||||
infer_opaque_hidden_type =
|
||||
opaque type's hidden type cannot be another opaque type from the same scope
|
||||
.label = one of the two opaque types used here has to be outside its defining scope
|
||||
.opaque_type = opaque type whose hidden type is being assigned
|
||||
.hidden_type = opaque type being used as hidden type
|
||||
|
||||
infer_type_annotations_needed = {$source_kind ->
|
||||
[closure] type annotations needed for the closure `{$source_name}`
|
||||
[normal] type annotations needed for `{$source_name}`
|
||||
*[other] type annotations needed
|
||||
}
|
||||
.label = type must be known at this point
|
||||
|
||||
infer_label_bad = {$bad_kind ->
|
||||
*[other] cannot infer type
|
||||
[more_info] cannot infer {$prefix_kind ->
|
||||
*[type] type for {$prefix}
|
||||
[const_with_param] the value of const parameter
|
||||
[const] the value of the constant
|
||||
} `{$name}`{$has_parent ->
|
||||
[true] {" "}declared on the {$parent_prefix} `{$parent_name}`
|
||||
*[false] {""}
|
||||
}
|
||||
}
|
||||
|
||||
infer_source_kind_subdiag_let = {$kind ->
|
||||
[with_pattern] consider giving `{$name}` an explicit type
|
||||
[closure] consider giving this closure parameter an explicit type
|
||||
*[other] consider giving this pattern a type
|
||||
}{$x_kind ->
|
||||
[has_name] , where the {$prefix_kind ->
|
||||
*[type] type for {$prefix}
|
||||
[const_with_param] the value of const parameter
|
||||
[const] the value of the constant
|
||||
} `{$arg_name}` is specified
|
||||
[underscore] , where the placeholders `_` are specified
|
||||
*[empty] {""}
|
||||
}
|
||||
|
||||
infer_source_kind_subdiag_generic_label =
|
||||
cannot infer {$is_type ->
|
||||
[true] type
|
||||
*[false] the value
|
||||
} of the {$is_type ->
|
||||
[true] type
|
||||
*[false] const
|
||||
} {$parent_exists ->
|
||||
[true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}`
|
||||
*[false] parameter {$param_name}
|
||||
}
|
||||
|
||||
infer_source_kind_subdiag_generic_suggestion =
|
||||
consider specifying the generic {$arg_count ->
|
||||
[one] argument
|
||||
*[other] arguments
|
||||
}
|
||||
|
||||
infer_source_kind_fully_qualified =
|
||||
try using a fully qualified path to specify the expected types
|
||||
|
||||
infer_source_kind_closure_return =
|
||||
try giving this closure an explicit return type
|
||||
|
||||
# generator_kind may need to be translated
|
||||
infer_need_type_info_in_generator =
|
||||
type inside {$generator_kind ->
|
||||
[async_block] `async` block
|
||||
[async_closure] `async` closure
|
||||
[async_fn] `async fn` body
|
||||
*[generator] generator
|
||||
} must be known in this context
|
||||
|
||||
|
||||
infer_subtype = ...so that the {$requirement ->
|
||||
[method_compat] method type is compatible with trait
|
||||
[type_compat] associated type is compatible with trait
|
||||
[const_compat] const is compatible with trait
|
||||
[expr_assignable] expression is assignable
|
||||
[if_else_different] `if` and `else` have incompatible types
|
||||
[no_else] `if` missing an `else` returns `()`
|
||||
[fn_main_correct_type] `main` function has the correct type
|
||||
[fn_start_correct_type] #[start]` function has the correct type
|
||||
[intristic_correct_type] intrinsic has the correct type
|
||||
[method_correct_type] method receiver has the correct type
|
||||
*[other] types are compatible
|
||||
}
|
||||
infer_subtype_2 = ...so that {$requirement ->
|
||||
[method_compat] method type is compatible with trait
|
||||
[type_compat] associated type is compatible with trait
|
||||
[const_compat] const is compatible with trait
|
||||
[expr_assignable] expression is assignable
|
||||
[if_else_different] `if` and `else` have incompatible types
|
||||
[no_else] `if` missing an `else` returns `()`
|
||||
[fn_main_correct_type] `main` function has the correct type
|
||||
[fn_start_correct_type] #[start]` function has the correct type
|
||||
[intristic_correct_type] intrinsic has the correct type
|
||||
[method_correct_type] method receiver has the correct type
|
||||
*[other] types are compatible
|
||||
}
|
||||
|
||||
infer_reborrow = ...so that reference does not outlive borrowed content
|
||||
infer_reborrow_upvar = ...so that closure can access `{$name}`
|
||||
infer_relate_object_bound = ...so that it can be closed over into an object
|
||||
infer_data_borrowed = ...so that the type `{$name}` is not borrowed for too long
|
||||
infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at
|
||||
infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues ->
|
||||
[true] ...
|
||||
*[false] {""}
|
||||
}
|
||||
infer_relate_param_bound_2 = ...that is required by this bound
|
||||
infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
|
||||
infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
|
@ -41,6 +41,7 @@ fluent_messages! {
|
||||
driver => "../locales/en-US/driver.ftl",
|
||||
expand => "../locales/en-US/expand.ftl",
|
||||
interface => "../locales/en-US/interface.ftl",
|
||||
infer => "../locales/en-US/infer.ftl",
|
||||
lint => "../locales/en-US/lint.ftl",
|
||||
parser => "../locales/en-US/parser.ftl",
|
||||
passes => "../locales/en-US/passes.ftl",
|
||||
|
@ -15,6 +15,7 @@ rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
|
254
compiler/rustc_infer/src/errors.rs
Normal file
254
compiler/rustc_infer/src/errors.rs
Normal file
@ -0,0 +1,254 @@
|
||||
use rustc_errors::{fluent, AddSubdiagnostic, DiagnosticMessage, DiagnosticStyledString};
|
||||
use rustc_hir::FnRetTy;
|
||||
use rustc_macros::SessionDiagnostic;
|
||||
use rustc_span::{BytePos, Span};
|
||||
|
||||
use crate::infer::error_reporting::{
|
||||
need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
|
||||
ObligationCauseAsDiagArg,
|
||||
};
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(infer::opaque_hidden_type)]
|
||||
pub struct OpaqueHiddenTypeDiag {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[note(infer::opaque_type)]
|
||||
pub opaque_type: Span,
|
||||
#[note(infer::hidden_type)]
|
||||
pub hidden_type: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(infer::type_annotations_needed, code = "E0282")]
|
||||
pub struct AnnotationRequired<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub source_kind: &'static str,
|
||||
pub source_name: &'a str,
|
||||
#[label]
|
||||
pub failure_span: Option<Span>,
|
||||
#[subdiagnostic]
|
||||
pub bad_label: Option<InferenceBadError<'a>>,
|
||||
#[subdiagnostic]
|
||||
pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
|
||||
#[subdiagnostic]
|
||||
pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
|
||||
}
|
||||
|
||||
// Copy of `AnnotationRequired` for E0283
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(infer::type_annotations_needed, code = "E0283")]
|
||||
pub struct AmbigousImpl<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub source_kind: &'static str,
|
||||
pub source_name: &'a str,
|
||||
#[label]
|
||||
pub failure_span: Option<Span>,
|
||||
#[subdiagnostic]
|
||||
pub bad_label: Option<InferenceBadError<'a>>,
|
||||
#[subdiagnostic]
|
||||
pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
|
||||
#[subdiagnostic]
|
||||
pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
|
||||
}
|
||||
|
||||
// Copy of `AnnotationRequired` for E0284
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(infer::type_annotations_needed, code = "E0284")]
|
||||
pub struct AmbigousReturn<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub source_kind: &'static str,
|
||||
pub source_name: &'a str,
|
||||
#[label]
|
||||
pub failure_span: Option<Span>,
|
||||
#[subdiagnostic]
|
||||
pub bad_label: Option<InferenceBadError<'a>>,
|
||||
#[subdiagnostic]
|
||||
pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
|
||||
#[subdiagnostic]
|
||||
pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(infer::need_type_info_in_generator, code = "E0698")]
|
||||
pub struct NeedTypeInfoInGenerator<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub generator_kind: GeneratorKindAsDiagArg,
|
||||
#[subdiagnostic]
|
||||
pub bad_label: InferenceBadError<'a>,
|
||||
}
|
||||
|
||||
// Used when a better one isn't available
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
#[label(infer::label_bad)]
|
||||
pub struct InferenceBadError<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub bad_kind: &'static str,
|
||||
pub prefix_kind: UnderspecifiedArgKind,
|
||||
pub has_parent: bool,
|
||||
pub prefix: &'a str,
|
||||
pub parent_prefix: &'a str,
|
||||
pub parent_name: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
pub enum SourceKindSubdiag<'a> {
|
||||
#[suggestion_verbose(
|
||||
infer::source_kind_subdiag_let,
|
||||
code = ": {type_name}",
|
||||
applicability = "has-placeholders"
|
||||
)]
|
||||
LetLike {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name: String,
|
||||
type_name: String,
|
||||
kind: &'static str,
|
||||
x_kind: &'static str,
|
||||
prefix_kind: UnderspecifiedArgKind,
|
||||
prefix: &'a str,
|
||||
arg_name: String,
|
||||
},
|
||||
#[label(infer::source_kind_subdiag_generic_label)]
|
||||
GenericLabel {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
is_type: bool,
|
||||
param_name: String,
|
||||
parent_exists: bool,
|
||||
parent_prefix: String,
|
||||
parent_name: String,
|
||||
},
|
||||
#[suggestion_verbose(
|
||||
infer::source_kind_subdiag_generic_suggestion,
|
||||
code = "::<{args}>",
|
||||
applicability = "has-placeholders"
|
||||
)]
|
||||
GenericSuggestion {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
arg_count: usize,
|
||||
args: String,
|
||||
},
|
||||
}
|
||||
|
||||
// Has to be implemented manually because multipart suggestions are not supported by the derive macro.
|
||||
// Would be a part of `SourceKindSubdiag` otherwise.
|
||||
pub enum SourceKindMultiSuggestion<'a> {
|
||||
FullyQualified {
|
||||
span: Span,
|
||||
def_path: String,
|
||||
adjustment: &'a str,
|
||||
successor: (&'a str, BytePos),
|
||||
},
|
||||
ClosureReturn {
|
||||
ty_info: String,
|
||||
data: &'a FnRetTy<'a>,
|
||||
should_wrap_expr: Option<Span>,
|
||||
},
|
||||
}
|
||||
|
||||
impl AddSubdiagnostic for SourceKindMultiSuggestion<'_> {
|
||||
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
|
||||
match self {
|
||||
Self::FullyQualified { span, def_path, adjustment, successor } => {
|
||||
let suggestion = vec![
|
||||
(span.shrink_to_lo(), format!("{def_path}({adjustment}")),
|
||||
(span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
|
||||
];
|
||||
diag.multipart_suggestion_verbose(
|
||||
fluent::infer::source_kind_fully_qualified,
|
||||
suggestion,
|
||||
rustc_errors::Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
Self::ClosureReturn { ty_info, data, should_wrap_expr } => {
|
||||
let (arrow, post) = match data {
|
||||
FnRetTy::DefaultReturn(_) => ("-> ", " "),
|
||||
_ => ("", ""),
|
||||
};
|
||||
let suggestion = match should_wrap_expr {
|
||||
Some(end_span) => vec![
|
||||
(data.span(), format!("{}{}{}{{ ", arrow, ty_info, post)),
|
||||
(end_span, " }".to_string()),
|
||||
],
|
||||
None => vec![(data.span(), format!("{}{}{}", arrow, ty_info, post))],
|
||||
};
|
||||
diag.multipart_suggestion_verbose(
|
||||
fluent::infer::source_kind_closure_return,
|
||||
suggestion,
|
||||
rustc_errors::Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum RegionOriginNote<'a> {
|
||||
Plain {
|
||||
span: Span,
|
||||
msg: DiagnosticMessage,
|
||||
},
|
||||
WithName {
|
||||
span: Span,
|
||||
msg: DiagnosticMessage,
|
||||
name: &'a str,
|
||||
continues: bool,
|
||||
},
|
||||
WithRequirement {
|
||||
span: Span,
|
||||
requirement: ObligationCauseAsDiagArg<'a>,
|
||||
expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
|
||||
},
|
||||
}
|
||||
|
||||
impl AddSubdiagnostic for RegionOriginNote<'_> {
|
||||
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
|
||||
let mut label_or_note = |span, msg: DiagnosticMessage| {
|
||||
let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
|
||||
let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
|
||||
let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
|
||||
if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
|
||||
diag.span_label(span, msg);
|
||||
} else if span_is_primary && expanded_sub_count == 0 {
|
||||
diag.note(msg);
|
||||
} else {
|
||||
diag.span_note(span, msg);
|
||||
}
|
||||
};
|
||||
match self {
|
||||
RegionOriginNote::Plain { span, msg } => {
|
||||
label_or_note(span, msg);
|
||||
}
|
||||
RegionOriginNote::WithName { span, msg, name, continues } => {
|
||||
label_or_note(span, msg);
|
||||
diag.set_arg("name", name);
|
||||
diag.set_arg("continues", continues);
|
||||
}
|
||||
RegionOriginNote::WithRequirement {
|
||||
span,
|
||||
requirement,
|
||||
expected_found: Some((expected, found)),
|
||||
} => {
|
||||
label_or_note(span, fluent::infer::subtype);
|
||||
diag.set_arg("requirement", requirement);
|
||||
|
||||
diag.note_expected_found(&"", expected, &"", found);
|
||||
}
|
||||
RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
|
||||
// FIXME: this really should be handled at some earlier stage. Our
|
||||
// handling of region checking when type errors are present is
|
||||
// *terrible*.
|
||||
label_or_note(span, fluent::infer::subtype_2);
|
||||
diag.set_arg("requirement", requirement);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -58,7 +58,7 @@ use crate::traits::{
|
||||
};
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
|
||||
use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
@ -78,7 +78,7 @@ use std::{cmp, fmt, iter};
|
||||
|
||||
mod note;
|
||||
|
||||
mod need_type_info;
|
||||
pub(crate) mod need_type_info;
|
||||
pub use need_type_info::TypeAnnotationNeeded;
|
||||
|
||||
pub mod nice_region_error;
|
||||
@ -1588,9 +1588,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
Mismatch::Variable(infer::ExpectedFound { expected, found }),
|
||||
)
|
||||
}
|
||||
ValuePairs::Terms(infer::ExpectedFound {
|
||||
expected: ty::Term::Const(_),
|
||||
found: ty::Term::Const(_),
|
||||
}) => (false, Mismatch::Fixed("constant")),
|
||||
ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
|
||||
(false, Mismatch::Fixed("trait"))
|
||||
}
|
||||
ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
|
||||
_ => (false, Mismatch::Fixed("type")),
|
||||
};
|
||||
let vals = match self.values_str(values) {
|
||||
@ -2881,6 +2886,30 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Newtype to allow implementing IntoDiagnosticArg
|
||||
pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>);
|
||||
|
||||
impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||
use crate::traits::ObligationCauseCode::*;
|
||||
let kind = match self.0.code() {
|
||||
CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat",
|
||||
CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => "type_compat",
|
||||
CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => "const_compat",
|
||||
ExprAssignable => "expr_assignable",
|
||||
IfExpression { .. } => "if_else_different",
|
||||
IfExpressionWithNoElse => "no_else",
|
||||
MainFunctionType => "fn_main_correct_type",
|
||||
StartFunctionType => "fn_start_correct_type",
|
||||
IntrinsicType => "intristic_correct_type",
|
||||
MethodReceiver => "method_correct_type",
|
||||
_ => "other",
|
||||
}
|
||||
.into();
|
||||
rustc_errors::DiagnosticArgValue::Str(kind)
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks
|
||||
/// extra information about each type, but we only care about the category.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
@ -1,6 +1,10 @@
|
||||
use crate::errors::{
|
||||
AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
|
||||
SourceKindMultiSuggestion, SourceKindSubdiag,
|
||||
};
|
||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::InferCtxt;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
||||
@ -14,6 +18,7 @@ use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
||||
use rustc_middle::ty::{self, DefIdTree, InferConst};
|
||||
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
|
||||
use rustc_session::SessionDiagnostic;
|
||||
use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::{BytePos, Span};
|
||||
use std::borrow::Cow;
|
||||
@ -60,38 +65,49 @@ pub struct InferenceDiagnosticsParentData {
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum UnderspecifiedArgKind {
|
||||
Type { prefix: Cow<'static, str> },
|
||||
Const { is_parameter: bool },
|
||||
}
|
||||
|
||||
impl InferenceDiagnosticsData {
|
||||
/// Generate a label for a generic argument which can't be inferred. When not
|
||||
/// much is known about the argument, `use_diag` may be used to describe the
|
||||
/// labeled value.
|
||||
fn cannot_infer_msg(&self) -> String {
|
||||
if self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }) {
|
||||
return "cannot infer type".to_string();
|
||||
}
|
||||
|
||||
let suffix = match &self.parent {
|
||||
Some(parent) => parent.suffix_string(),
|
||||
None => String::new(),
|
||||
};
|
||||
|
||||
// For example: "cannot infer type for type parameter `T`"
|
||||
format!("cannot infer {} `{}`{}", self.kind.prefix_string(), self.name, suffix)
|
||||
fn can_add_more_info(&self) -> bool {
|
||||
!(self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }))
|
||||
}
|
||||
|
||||
fn where_x_is_specified(&self, in_type: Ty<'_>) -> String {
|
||||
fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str {
|
||||
if in_type.is_ty_infer() {
|
||||
String::new()
|
||||
"empty"
|
||||
} else if self.name == "_" {
|
||||
// FIXME: Consider specializing this message if there is a single `_`
|
||||
// in the type.
|
||||
", where the placeholders `_` are specified".to_string()
|
||||
"underscore"
|
||||
} else {
|
||||
format!(", where the {} `{}` is specified", self.kind.prefix_string(), self.name)
|
||||
"has_name"
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a label for a generic argument which can't be inferred. When not
|
||||
/// much is known about the argument, `use_diag` may be used to describe the
|
||||
/// labeled value.
|
||||
fn make_bad_error(&self, span: Span) -> InferenceBadError<'_> {
|
||||
let has_parent = self.parent.is_some();
|
||||
let bad_kind = if self.can_add_more_info() { "more_info" } else { "other" };
|
||||
let (parent_prefix, parent_name) = self
|
||||
.parent
|
||||
.as_ref()
|
||||
.map(|parent| (parent.prefix, parent.name.clone()))
|
||||
.unwrap_or_default();
|
||||
InferenceBadError {
|
||||
span,
|
||||
bad_kind,
|
||||
prefix_kind: self.kind.clone(),
|
||||
prefix: self.kind.try_get_prefix().unwrap_or_default(),
|
||||
name: self.name.clone(),
|
||||
has_parent,
|
||||
parent_prefix,
|
||||
parent_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -113,18 +129,24 @@ impl InferenceDiagnosticsParentData {
|
||||
fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
|
||||
Self::for_parent_def_id(tcx, tcx.parent(def_id))
|
||||
}
|
||||
}
|
||||
|
||||
fn suffix_string(&self) -> String {
|
||||
format!(" declared on the {} `{}`", self.prefix, self.name)
|
||||
impl IntoDiagnosticArg for UnderspecifiedArgKind {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||
let kind = match self {
|
||||
Self::Type { .. } => "type",
|
||||
Self::Const { is_parameter: true } => "const_with_param",
|
||||
Self::Const { is_parameter: false } => "const",
|
||||
};
|
||||
rustc_errors::DiagnosticArgValue::Str(kind.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl UnderspecifiedArgKind {
|
||||
fn prefix_string(&self) -> Cow<'static, str> {
|
||||
fn try_get_prefix(&self) -> Option<&str> {
|
||||
match self {
|
||||
Self::Type { prefix } => format!("type for {}", prefix).into(),
|
||||
Self::Const { is_parameter: true } => "the value of const parameter".into(),
|
||||
Self::Const { is_parameter: false } => "the value of the constant".into(),
|
||||
Self::Type { prefix } => Some(prefix.as_ref()),
|
||||
Self::Const { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -303,11 +325,44 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
arg_data: InferenceDiagnosticsData,
|
||||
error_code: TypeAnnotationNeeded,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let error_code = error_code.into();
|
||||
let mut err =
|
||||
self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code);
|
||||
err.span_label(span, arg_data.cannot_infer_msg());
|
||||
err
|
||||
let source_kind = "other";
|
||||
let source_name = "";
|
||||
let failure_span = None;
|
||||
let infer_subdiags = Vec::new();
|
||||
let multi_suggestions = Vec::new();
|
||||
let bad_label = Some(arg_data.make_bad_error(span));
|
||||
match error_code {
|
||||
TypeAnnotationNeeded::E0282 => AnnotationRequired {
|
||||
span,
|
||||
source_kind,
|
||||
source_name,
|
||||
failure_span,
|
||||
infer_subdiags,
|
||||
multi_suggestions,
|
||||
bad_label,
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess),
|
||||
TypeAnnotationNeeded::E0283 => AmbigousImpl {
|
||||
span,
|
||||
source_kind,
|
||||
source_name,
|
||||
failure_span,
|
||||
infer_subdiags,
|
||||
multi_suggestions,
|
||||
bad_label,
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess),
|
||||
TypeAnnotationNeeded::E0284 => AmbigousReturn {
|
||||
span,
|
||||
source_kind,
|
||||
source_name,
|
||||
failure_span,
|
||||
infer_subdiags,
|
||||
multi_suggestions,
|
||||
bad_label,
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_inference_failure_err(
|
||||
@ -340,48 +395,39 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
return self.bad_inference_failure_err(failure_span, arg_data, error_code)
|
||||
};
|
||||
|
||||
let error_code = error_code.into();
|
||||
let mut err = self.tcx.sess.struct_span_err_with_code(
|
||||
span,
|
||||
&format!("type annotations needed{}", kind.ty_msg(self)),
|
||||
error_code,
|
||||
);
|
||||
|
||||
if should_label_span && !failure_span.overlaps(span) {
|
||||
err.span_label(failure_span, "type must be known at this point");
|
||||
}
|
||||
let (source_kind, name) = kind.ty_localized_msg(self);
|
||||
let failure_span = if should_label_span && !failure_span.overlaps(span) {
|
||||
Some(failure_span)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut infer_subdiags = Vec::new();
|
||||
let mut multi_suggestions = Vec::new();
|
||||
match kind {
|
||||
InferSourceKind::LetBinding { insert_span, pattern_name, ty } => {
|
||||
let suggestion_msg = if let Some(name) = pattern_name {
|
||||
format!(
|
||||
"consider giving `{}` an explicit type{}",
|
||||
name,
|
||||
arg_data.where_x_is_specified(ty)
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"consider giving this pattern a type{}",
|
||||
arg_data.where_x_is_specified(ty)
|
||||
)
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
insert_span,
|
||||
&suggestion_msg,
|
||||
format!(": {}", ty_to_string(self, ty)),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
infer_subdiags.push(SourceKindSubdiag::LetLike {
|
||||
span: insert_span,
|
||||
name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new),
|
||||
x_kind: arg_data.where_x_is_kind(ty),
|
||||
prefix_kind: arg_data.kind.clone(),
|
||||
prefix: arg_data.kind.try_get_prefix().unwrap_or_default(),
|
||||
arg_name: arg_data.name,
|
||||
kind: if pattern_name.is_some() { "with_pattern" } else { "other" },
|
||||
type_name: ty_to_string(self, ty),
|
||||
});
|
||||
}
|
||||
InferSourceKind::ClosureArg { insert_span, ty } => {
|
||||
err.span_suggestion_verbose(
|
||||
insert_span,
|
||||
&format!(
|
||||
"consider giving this closure parameter an explicit type{}",
|
||||
arg_data.where_x_is_specified(ty)
|
||||
),
|
||||
format!(": {}", ty_to_string(self, ty)),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
infer_subdiags.push(SourceKindSubdiag::LetLike {
|
||||
span: insert_span,
|
||||
name: String::new(),
|
||||
x_kind: arg_data.where_x_is_kind(ty),
|
||||
prefix_kind: arg_data.kind.clone(),
|
||||
prefix: arg_data.kind.try_get_prefix().unwrap_or_default(),
|
||||
arg_name: arg_data.name,
|
||||
kind: "closure",
|
||||
type_name: ty_to_string(self, ty),
|
||||
});
|
||||
}
|
||||
InferSourceKind::GenericArg {
|
||||
insert_span,
|
||||
@ -393,19 +439,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let generics = self.tcx.generics_of(generics_def_id);
|
||||
let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
|
||||
|
||||
let cannot_infer_msg = format!(
|
||||
"cannot infer {} of the {} parameter `{}`{}",
|
||||
if is_type { "type" } else { "the value" },
|
||||
if is_type { "type" } else { "const" },
|
||||
generics.params[argument_index].name,
|
||||
// We use the `generics_def_id` here, as even when suggesting `None::<T>`,
|
||||
// the type parameter `T` was still declared on the enum, not on the
|
||||
// variant.
|
||||
let (parent_exists, parent_prefix, parent_name) =
|
||||
InferenceDiagnosticsParentData::for_parent_def_id(self.tcx, generics_def_id)
|
||||
.map_or(String::new(), |parent| parent.suffix_string()),
|
||||
);
|
||||
.map_or((false, String::new(), String::new()), |parent| {
|
||||
(true, parent.prefix.to_string(), parent.name)
|
||||
});
|
||||
|
||||
err.span_label(span, cannot_infer_msg);
|
||||
infer_subdiags.push(SourceKindSubdiag::GenericLabel {
|
||||
span,
|
||||
is_type,
|
||||
param_name: generics.params[argument_index].name.to_string(),
|
||||
parent_exists,
|
||||
parent_prefix,
|
||||
parent_name,
|
||||
});
|
||||
|
||||
let args = fmt_printer(self, Namespace::TypeNS)
|
||||
.comma_sep(generic_args.iter().copied().map(|arg| {
|
||||
@ -435,15 +482,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
.unwrap()
|
||||
.into_buffer();
|
||||
|
||||
err.span_suggestion_verbose(
|
||||
insert_span,
|
||||
&format!(
|
||||
"consider specifying the generic argument{}",
|
||||
pluralize!(generic_args.len()),
|
||||
),
|
||||
format!("::<{}>", args),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
infer_subdiags.push(SourceKindSubdiag::GenericSuggestion {
|
||||
span: insert_span,
|
||||
arg_count: generic_args.len(),
|
||||
args,
|
||||
});
|
||||
}
|
||||
InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => {
|
||||
let printer = fmt_printer(self, Namespace::ValueNS);
|
||||
@ -468,37 +511,54 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
_ => "",
|
||||
};
|
||||
|
||||
let suggestion = vec![
|
||||
(receiver.span.shrink_to_lo(), format!("{def_path}({adjustment}")),
|
||||
(receiver.span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
|
||||
];
|
||||
err.multipart_suggestion_verbose(
|
||||
"try using a fully qualified path to specify the expected types",
|
||||
suggestion,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
multi_suggestions.push(SourceKindMultiSuggestion::FullyQualified {
|
||||
span: receiver.span,
|
||||
def_path,
|
||||
adjustment,
|
||||
successor,
|
||||
});
|
||||
}
|
||||
InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
|
||||
let ret = ty_to_string(self, ty);
|
||||
let (arrow, post) = match data {
|
||||
FnRetTy::DefaultReturn(_) => ("-> ", " "),
|
||||
_ => ("", ""),
|
||||
};
|
||||
let suggestion = match should_wrap_expr {
|
||||
Some(end_span) => vec![
|
||||
(data.span(), format!("{}{}{}{{ ", arrow, ret, post)),
|
||||
(end_span, " }".to_string()),
|
||||
],
|
||||
None => vec![(data.span(), format!("{}{}{}", arrow, ret, post))],
|
||||
};
|
||||
err.multipart_suggestion_verbose(
|
||||
"try giving this closure an explicit return type",
|
||||
suggestion,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
let ty_info = ty_to_string(self, ty);
|
||||
multi_suggestions.push(SourceKindMultiSuggestion::ClosureReturn {
|
||||
ty_info,
|
||||
data,
|
||||
should_wrap_expr,
|
||||
});
|
||||
}
|
||||
}
|
||||
err
|
||||
match error_code {
|
||||
TypeAnnotationNeeded::E0282 => AnnotationRequired {
|
||||
span,
|
||||
source_kind,
|
||||
source_name: &name,
|
||||
failure_span,
|
||||
infer_subdiags,
|
||||
multi_suggestions,
|
||||
bad_label: None,
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess),
|
||||
TypeAnnotationNeeded::E0283 => AmbigousImpl {
|
||||
span,
|
||||
source_kind,
|
||||
source_name: &name,
|
||||
failure_span,
|
||||
infer_subdiags,
|
||||
multi_suggestions,
|
||||
bad_label: None,
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess),
|
||||
TypeAnnotationNeeded::E0284 => AmbigousReturn {
|
||||
span,
|
||||
source_kind,
|
||||
source_name: &name,
|
||||
failure_span,
|
||||
infer_subdiags,
|
||||
multi_suggestions,
|
||||
bad_label: None,
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn need_type_info_err_in_generator(
|
||||
@ -510,15 +570,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let ty = self.resolve_vars_if_possible(ty);
|
||||
let data = self.extract_inference_diagnostics_data(ty.into(), None);
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
NeedTypeInfoInGenerator {
|
||||
bad_label: data.make_bad_error(span),
|
||||
span,
|
||||
E0698,
|
||||
"type inside {} must be known in this context",
|
||||
kind,
|
||||
);
|
||||
err.span_label(span, data.cannot_infer_msg());
|
||||
err
|
||||
generator_kind: GeneratorKindAsDiagArg(kind),
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GeneratorKindAsDiagArg(pub hir::GeneratorKind);
|
||||
|
||||
impl IntoDiagnosticArg for GeneratorKindAsDiagArg {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||
let kind = match self.0 {
|
||||
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "async_block",
|
||||
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "async_closure",
|
||||
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "async_fn",
|
||||
hir::GeneratorKind::Gen => "generator",
|
||||
};
|
||||
rustc_errors::DiagnosticArgValue::Str(kind.into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -579,22 +650,22 @@ impl<'tcx> InferSource<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> InferSourceKind<'tcx> {
|
||||
fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String {
|
||||
fn ty_localized_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> (&'static str, String) {
|
||||
match *self {
|
||||
InferSourceKind::LetBinding { ty, .. }
|
||||
| InferSourceKind::ClosureArg { ty, .. }
|
||||
| InferSourceKind::ClosureReturn { ty, .. } => {
|
||||
if ty.is_closure() {
|
||||
format!(" for the closure `{}`", closure_as_fn_str(infcx, ty))
|
||||
("closure", closure_as_fn_str(infcx, ty))
|
||||
} else if !ty.is_ty_infer() {
|
||||
format!(" for `{}`", ty_to_string(infcx, ty))
|
||||
("normal", ty_to_string(infcx, ty))
|
||||
} else {
|
||||
String::new()
|
||||
("other", String::new())
|
||||
}
|
||||
}
|
||||
// FIXME: We should be able to add some additional info here.
|
||||
InferSourceKind::GenericArg { .. }
|
||||
| InferSourceKind::FullyQualifiedMethodCall { .. } => String::new(),
|
||||
| InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,96 +1,78 @@
|
||||
use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt};
|
||||
use crate::errors::RegionOriginNote;
|
||||
use crate::infer::error_reporting::note_and_explain_region;
|
||||
use crate::infer::{self, InferCtxt, SubregionOrigin};
|
||||
use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_errors::{
|
||||
fluent, struct_span_err, AddSubdiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||
};
|
||||
use rustc_middle::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::{self, Region};
|
||||
|
||||
use super::ObligationCauseAsDiagArg;
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
|
||||
let mut label_or_note = |span, msg: &str| {
|
||||
let sub_count = err.children.iter().filter(|d| d.span.is_dummy()).count();
|
||||
let expanded_sub_count = err.children.iter().filter(|d| !d.span.is_dummy()).count();
|
||||
let span_is_primary = err.span.primary_spans().iter().all(|&sp| sp == span);
|
||||
if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
|
||||
err.span_label(span, msg);
|
||||
} else if span_is_primary && expanded_sub_count == 0 {
|
||||
err.note(msg);
|
||||
} else {
|
||||
err.span_note(span, msg);
|
||||
}
|
||||
};
|
||||
match *origin {
|
||||
infer::Subtype(ref trace) => {
|
||||
if let Some((expected, found)) = self.values_str(trace.values) {
|
||||
label_or_note(
|
||||
trace.cause.span,
|
||||
&format!("...so that the {}", trace.cause.as_requirement_str()),
|
||||
);
|
||||
|
||||
err.note_expected_found(&"", expected, &"", found);
|
||||
} else {
|
||||
// FIXME: this really should be handled at some earlier stage. Our
|
||||
// handling of region checking when type errors are present is
|
||||
// *terrible*.
|
||||
|
||||
label_or_note(
|
||||
trace.cause.span,
|
||||
&format!("...so that {}", trace.cause.as_requirement_str()),
|
||||
);
|
||||
}
|
||||
}
|
||||
infer::Reborrow(span) => {
|
||||
label_or_note(span, "...so that reference does not outlive borrowed content");
|
||||
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
|
||||
span: trace.cause.span,
|
||||
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
|
||||
expected_found: self.values_str(trace.values),
|
||||
}
|
||||
.add_to_diagnostic(err),
|
||||
infer::Reborrow(span) => RegionOriginNote::Plain { span, msg: fluent::infer::reborrow }
|
||||
.add_to_diagnostic(err),
|
||||
infer::ReborrowUpvar(span, ref upvar_id) => {
|
||||
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
|
||||
label_or_note(span, &format!("...so that closure can access `{}`", var_name));
|
||||
RegionOriginNote::WithName {
|
||||
span,
|
||||
msg: fluent::infer::reborrow,
|
||||
name: &var_name.to_string(),
|
||||
continues: false,
|
||||
}
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
infer::RelateObjectBound(span) => {
|
||||
label_or_note(span, "...so that it can be closed over into an object");
|
||||
RegionOriginNote::Plain { span, msg: fluent::infer::relate_object_bound }
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
infer::DataBorrowed(ty, span) => {
|
||||
label_or_note(
|
||||
RegionOriginNote::WithName {
|
||||
span,
|
||||
&format!(
|
||||
"...so that the type `{}` is not borrowed for too long",
|
||||
self.ty_to_string(ty)
|
||||
),
|
||||
);
|
||||
msg: fluent::infer::data_borrowed,
|
||||
name: &self.ty_to_string(ty),
|
||||
continues: false,
|
||||
}
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||
label_or_note(
|
||||
RegionOriginNote::WithName {
|
||||
span,
|
||||
&format!(
|
||||
"...so that the reference type `{}` does not outlive the data it points at",
|
||||
self.ty_to_string(ty)
|
||||
),
|
||||
);
|
||||
msg: fluent::infer::reference_outlives_referent,
|
||||
name: &self.ty_to_string(ty),
|
||||
continues: false,
|
||||
}
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
infer::RelateParamBound(span, t, opt_span) => {
|
||||
label_or_note(
|
||||
infer::RelateParamBound(span, ty, opt_span) => {
|
||||
RegionOriginNote::WithName {
|
||||
span,
|
||||
&format!(
|
||||
"...so that the type `{}` will meet its required lifetime bounds{}",
|
||||
self.ty_to_string(t),
|
||||
if opt_span.is_some() { "..." } else { "" },
|
||||
),
|
||||
);
|
||||
msg: fluent::infer::relate_param_bound,
|
||||
name: &self.ty_to_string(ty),
|
||||
continues: opt_span.is_some(),
|
||||
}
|
||||
.add_to_diagnostic(err);
|
||||
if let Some(span) = opt_span {
|
||||
err.span_note(span, "...that is required by this bound");
|
||||
RegionOriginNote::Plain { span, msg: fluent::infer::relate_param_bound_2 }
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
}
|
||||
infer::RelateRegionParamBound(span) => {
|
||||
label_or_note(
|
||||
span,
|
||||
"...so that the declared lifetime parameter bounds are satisfied",
|
||||
);
|
||||
RegionOriginNote::Plain { span, msg: fluent::infer::relate_region_param_bound }
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
infer::CompareImplItemObligation { span, .. } => {
|
||||
label_or_note(
|
||||
span,
|
||||
"...so that the definition in impl matches the definition from the trait",
|
||||
);
|
||||
RegionOriginNote::Plain { span, msg: fluent::infer::compare_impl_item_obligation }
|
||||
.add_to_diagnostic(err);
|
||||
}
|
||||
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
|
||||
self.note_region_origin(err, &parent);
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::errors::OpaqueHiddenTypeDiag;
|
||||
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
|
||||
use crate::traits;
|
||||
use hir::def_id::{DefId, LocalDefId};
|
||||
@ -153,22 +154,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
if let Some(OpaqueTyOrigin::TyAlias) =
|
||||
did2.as_local().and_then(|did2| self.opaque_type_origin(did2, cause.span))
|
||||
{
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
cause.span,
|
||||
"opaque type's hidden type cannot be another opaque type from the same scope",
|
||||
)
|
||||
.span_label(cause.span, "one of the two opaque types used here has to be outside its defining scope")
|
||||
.span_note(
|
||||
self.tcx.def_span(def_id),
|
||||
"opaque type whose hidden type is being assigned",
|
||||
)
|
||||
.span_note(
|
||||
self.tcx.def_span(did2),
|
||||
"opaque type being used as hidden type",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
|
||||
span: cause.span,
|
||||
hidden_type: self.tcx.def_span(did2),
|
||||
opaque_type: self.tcx.def_span(def_id),
|
||||
});
|
||||
}
|
||||
}
|
||||
Some(self.register_hidden_type(
|
||||
|
@ -34,5 +34,6 @@ extern crate tracing;
|
||||
#[macro_use]
|
||||
extern crate rustc_middle;
|
||||
|
||||
mod errors;
|
||||
pub mod infer;
|
||||
pub mod traits;
|
||||
|
@ -148,9 +148,9 @@ impl DiagnosticDeriveBuilder {
|
||||
// `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug.
|
||||
Meta::List(MetaList { ref nested, .. }) => nested,
|
||||
// Subdiagnostics without spans can be applied to the type too, and these are just
|
||||
// paths: `#[help]`, `#[note]` and `#[warn_]`
|
||||
// paths: `#[help]`, `#[note]` and `#[warning]`
|
||||
Meta::Path(_) if !is_diag => {
|
||||
let fn_name = if name == "warn_" {
|
||||
let fn_name = if name == "warning" {
|
||||
Ident::new("warn", attr.span())
|
||||
} else {
|
||||
Ident::new(name, attr.span())
|
||||
@ -163,12 +163,15 @@ impl DiagnosticDeriveBuilder {
|
||||
// Check the kind before doing any further processing so that there aren't misleading
|
||||
// "no kind specified" errors if there are failures later.
|
||||
match name {
|
||||
"error" | "warning" | "lint" => throw_invalid_attr!(attr, &meta, |diag| {
|
||||
diag.help("`error`, `warning` and `lint` have been replaced by `diag`")
|
||||
"error" | "lint" => throw_invalid_attr!(attr, &meta, |diag| {
|
||||
diag.help("`error` and `lint` have been replaced by `diag`")
|
||||
}),
|
||||
"diag" | "help" | "note" | "warn_" => (),
|
||||
"warn_" => throw_invalid_attr!(attr, &meta, |diag| {
|
||||
diag.help("`warn_` have been replaced by `warning`")
|
||||
}),
|
||||
"diag" | "help" | "note" | "warning" => (),
|
||||
_ => throw_invalid_attr!(attr, &meta, |diag| {
|
||||
diag.help("only `diag`, `help`, `note` and `warn_` are valid attributes")
|
||||
diag.help("only `diag`, `help`, `note` and `warning` are valid attributes")
|
||||
}),
|
||||
}
|
||||
|
||||
@ -180,7 +183,7 @@ impl DiagnosticDeriveBuilder {
|
||||
if !is_diag && nested_iter.next().is_some() {
|
||||
throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
|
||||
diag.help(
|
||||
"`help`, `note` and `warn_` struct attributes can only have one argument",
|
||||
"`help`, `note` and `warning` struct attributes can only have one argument",
|
||||
)
|
||||
});
|
||||
}
|
||||
@ -348,12 +351,12 @@ impl DiagnosticDeriveBuilder {
|
||||
report_error_if_not_applied_to_span(attr, &info)?;
|
||||
Ok(self.add_spanned_subdiagnostic(binding, ident, parse_quote! { _subdiag::label }))
|
||||
}
|
||||
"note" | "help" | "warn_" => {
|
||||
"note" | "help" | "warning" => {
|
||||
let warn_ident = Ident::new("warn", Span::call_site());
|
||||
let (ident, path) = match name {
|
||||
"note" => (ident, parse_quote! { _subdiag::note }),
|
||||
"help" => (ident, parse_quote! { _subdiag::help }),
|
||||
"warn_" => (&warn_ident, parse_quote! { _subdiag::warn }),
|
||||
"warning" => (&warn_ident, parse_quote! { _subdiag::warn }),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
|
||||
@ -390,7 +393,7 @@ impl DiagnosticDeriveBuilder {
|
||||
"suggestion" | "suggestion_short" | "suggestion_hidden" | "suggestion_verbose" => {
|
||||
return self.generate_inner_field_code_suggestion(attr, info);
|
||||
}
|
||||
"label" | "help" | "note" | "warn_" => (),
|
||||
"label" | "help" | "note" | "warning" => (),
|
||||
_ => throw_invalid_attr!(attr, &meta, |diag| {
|
||||
diag.help(
|
||||
"only `label`, `help`, `note`, `warn` or `suggestion{,_short,_hidden,_verbose}` are \
|
||||
@ -422,14 +425,14 @@ impl DiagnosticDeriveBuilder {
|
||||
Ok(self.add_spanned_subdiagnostic(binding, ident, msg))
|
||||
}
|
||||
"note" | "help" if type_is_unit(&info.ty) => Ok(self.add_subdiagnostic(ident, msg)),
|
||||
// `warn_` must be special-cased because the attribute `warn` already has meaning and
|
||||
// `warning` must be special-cased because the attribute `warn` already has meaning and
|
||||
// so isn't used, despite the diagnostic API being named `warn`.
|
||||
"warn_" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => Ok(self
|
||||
"warning" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => Ok(self
|
||||
.add_spanned_subdiagnostic(binding, &Ident::new("warn", Span::call_site()), msg)),
|
||||
"warn_" if type_is_unit(&info.ty) => {
|
||||
"warning" if type_is_unit(&info.ty) => {
|
||||
Ok(self.add_subdiagnostic(&Ident::new("warn", Span::call_site()), msg))
|
||||
}
|
||||
"note" | "help" | "warn_" => report_type_error(attr, "`Span` or `()`")?,
|
||||
"note" | "help" | "warning" => report_type_error(attr, "`Span` or `()`")?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ enum SubdiagnosticKind {
|
||||
Note,
|
||||
/// `#[help(...)]`
|
||||
Help,
|
||||
/// `#[warn_(...)]`
|
||||
/// `#[warning(...)]`
|
||||
Warn,
|
||||
/// `#[suggestion{,_short,_hidden,_verbose}]`
|
||||
Suggestion(SubdiagnosticSuggestionKind),
|
||||
@ -51,7 +51,7 @@ impl FromStr for SubdiagnosticKind {
|
||||
"label" => Ok(SubdiagnosticKind::Label),
|
||||
"note" => Ok(SubdiagnosticKind::Note),
|
||||
"help" => Ok(SubdiagnosticKind::Help),
|
||||
"warn_" => Ok(SubdiagnosticKind::Warn),
|
||||
"warning" => Ok(SubdiagnosticKind::Warn),
|
||||
"suggestion" => Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal)),
|
||||
"suggestion_short" => {
|
||||
Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short))
|
||||
|
@ -132,7 +132,7 @@ decl_derive!(
|
||||
diag,
|
||||
help,
|
||||
note,
|
||||
warn_,
|
||||
warning,
|
||||
// field attributes
|
||||
skip_arg,
|
||||
primary_span,
|
||||
@ -149,7 +149,7 @@ decl_derive!(
|
||||
diag,
|
||||
help,
|
||||
note,
|
||||
warn_,
|
||||
warning,
|
||||
// field attributes
|
||||
skip_arg,
|
||||
primary_span,
|
||||
@ -166,7 +166,7 @@ decl_derive!(
|
||||
label,
|
||||
help,
|
||||
note,
|
||||
warn_,
|
||||
warning,
|
||||
suggestion,
|
||||
suggestion_short,
|
||||
suggestion_hidden,
|
||||
|
@ -12,14 +12,14 @@ pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Grap
|
||||
|
||||
// Nodes
|
||||
let nodes: Vec<Node> = body
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.iter_enumerated()
|
||||
.map(|(block, _)| bb_to_graph_node(block, body, dark_mode))
|
||||
.collect();
|
||||
|
||||
// Edges
|
||||
let mut edges = Vec::new();
|
||||
for (source, _) in body.basic_blocks().iter_enumerated() {
|
||||
for (source, _) in body.basic_blocks.iter_enumerated() {
|
||||
let def_id = body.source.def_id();
|
||||
let terminator = body[source].terminator();
|
||||
let labels = terminator.kind.fmt_successor_labels();
|
||||
|
@ -331,11 +331,6 @@ impl<'tcx> Body<'tcx> {
|
||||
body
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
|
||||
&self.basic_blocks
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
|
||||
self.basic_blocks.as_mut()
|
||||
@ -490,7 +485,7 @@ impl<'tcx> Index<BasicBlock> for Body<'tcx> {
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
|
||||
&self.basic_blocks()[index]
|
||||
&self.basic_blocks[index]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ pub struct MirPatch<'tcx> {
|
||||
impl<'tcx> MirPatch<'tcx> {
|
||||
pub fn new(body: &Body<'tcx>) -> Self {
|
||||
let mut result = MirPatch {
|
||||
patch_map: IndexVec::from_elem(None, body.basic_blocks()),
|
||||
patch_map: IndexVec::from_elem(None, &body.basic_blocks),
|
||||
new_blocks: vec![],
|
||||
new_statements: vec![],
|
||||
new_locals: vec![],
|
||||
@ -29,7 +29,7 @@ impl<'tcx> MirPatch<'tcx> {
|
||||
};
|
||||
|
||||
// Check if we already have a resume block
|
||||
for (bb, block) in body.basic_blocks().iter_enumerated() {
|
||||
for (bb, block) in body.basic_blocks.iter_enumerated() {
|
||||
if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() {
|
||||
result.resume_block = Some(bb);
|
||||
break;
|
||||
@ -61,7 +61,7 @@ impl<'tcx> MirPatch<'tcx> {
|
||||
}
|
||||
|
||||
pub fn terminator_loc(&self, body: &Body<'tcx>, bb: BasicBlock) -> Location {
|
||||
let offset = match bb.index().checked_sub(body.basic_blocks().len()) {
|
||||
let offset = match bb.index().checked_sub(body.basic_blocks.len()) {
|
||||
Some(index) => self.new_blocks[index].statements.len(),
|
||||
None => body[bb].statements.len(),
|
||||
};
|
||||
@ -129,7 +129,7 @@ impl<'tcx> MirPatch<'tcx> {
|
||||
debug!(
|
||||
"MirPatch: {} new blocks, starting from index {}",
|
||||
self.new_blocks.len(),
|
||||
body.basic_blocks().len()
|
||||
body.basic_blocks.len()
|
||||
);
|
||||
let bbs = if self.patch_map.is_empty() && self.new_blocks.is_empty() {
|
||||
body.basic_blocks.as_mut_preserves_cfg()
|
||||
@ -173,7 +173,7 @@ impl<'tcx> MirPatch<'tcx> {
|
||||
}
|
||||
|
||||
pub fn source_info_for_location(&self, body: &Body<'tcx>, loc: Location) -> SourceInfo {
|
||||
let data = match loc.block.index().checked_sub(body.basic_blocks().len()) {
|
||||
let data = match loc.block.index().checked_sub(body.basic_blocks.len()) {
|
||||
Some(new) => &self.new_blocks[new],
|
||||
None => &body[loc.block],
|
||||
};
|
||||
|
@ -318,10 +318,10 @@ where
|
||||
F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
|
||||
{
|
||||
write_mir_intro(tcx, body, w)?;
|
||||
for block in body.basic_blocks().indices() {
|
||||
for block in body.basic_blocks.indices() {
|
||||
extra_data(PassWhere::BeforeBlock(block), w)?;
|
||||
write_basic_block(tcx, block, body, extra_data, w)?;
|
||||
if block.index() + 1 != body.basic_blocks().len() {
|
||||
if block.index() + 1 != body.basic_blocks.len() {
|
||||
writeln!(w)?;
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ where
|
||||
}
|
||||
let body_span = hir_body.unwrap().value.span;
|
||||
let mut span_viewables = Vec::new();
|
||||
for (bb, data) in body.basic_blocks().iter_enumerated() {
|
||||
for (bb, data) in body.basic_blocks.iter_enumerated() {
|
||||
match spanview {
|
||||
MirSpanview::Statement => {
|
||||
for (i, statement) in data.statements.iter().enumerate() {
|
||||
|
@ -37,7 +37,7 @@ impl<'a, 'tcx> Preorder<'a, 'tcx> {
|
||||
|
||||
Preorder {
|
||||
body,
|
||||
visited: BitSet::new_empty(body.basic_blocks().len()),
|
||||
visited: BitSet::new_empty(body.basic_blocks.len()),
|
||||
worklist,
|
||||
root_is_start_block: root == START_BLOCK,
|
||||
}
|
||||
@ -71,7 +71,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
// All the blocks, minus the number of blocks we've visited.
|
||||
let upper = self.body.basic_blocks().len() - self.visited.count();
|
||||
let upper = self.body.basic_blocks.len() - self.visited.count();
|
||||
|
||||
let lower = if self.root_is_start_block {
|
||||
// We will visit all remaining blocks exactly once.
|
||||
|
@ -951,7 +951,7 @@ macro_rules! basic_blocks {
|
||||
$body.basic_blocks.as_mut_preserves_cfg()
|
||||
};
|
||||
($body:ident,) => {
|
||||
$body.basic_blocks()
|
||||
$body.basic_blocks
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -469,6 +469,13 @@ impl<'tcx> ObligationCauseCode<'tcx> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peel_match_impls(&self) -> &Self {
|
||||
match self {
|
||||
MatchImpl(cause, _) => cause.code(),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||
|
@ -272,7 +272,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
|
||||
// by borrow checking.
|
||||
debug_assert!(
|
||||
!(body.local_decls.has_free_regions()
|
||||
|| body.basic_blocks().has_free_regions()
|
||||
|| body.basic_blocks.has_free_regions()
|
||||
|| body.var_debug_info.has_free_regions()
|
||||
|| body.yield_ty().has_free_regions()),
|
||||
"Unexpected free regions in MIR: {:?}",
|
||||
|
@ -111,9 +111,9 @@ where
|
||||
// Otherwise, compute and store the cumulative transfer function for each block.
|
||||
|
||||
let identity = GenKillSet::identity(analysis.bottom_value(body).domain_size());
|
||||
let mut trans_for_block = IndexVec::from_elem(identity, body.basic_blocks());
|
||||
let mut trans_for_block = IndexVec::from_elem(identity, &body.basic_blocks);
|
||||
|
||||
for (block, block_data) in body.basic_blocks().iter_enumerated() {
|
||||
for (block, block_data) in body.basic_blocks.iter_enumerated() {
|
||||
let trans = &mut trans_for_block[block];
|
||||
A::Direction::gen_kill_effects_in_block(&analysis, trans, block, block_data);
|
||||
}
|
||||
@ -147,7 +147,7 @@ where
|
||||
apply_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
|
||||
) -> Self {
|
||||
let bottom_value = analysis.bottom_value(body);
|
||||
let mut entry_sets = IndexVec::from_elem(bottom_value.clone(), body.basic_blocks());
|
||||
let mut entry_sets = IndexVec::from_elem(bottom_value.clone(), &body.basic_blocks);
|
||||
analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
|
||||
|
||||
if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != bottom_value {
|
||||
@ -200,8 +200,7 @@ where
|
||||
..
|
||||
} = self;
|
||||
|
||||
let mut dirty_queue: WorkQueue<BasicBlock> =
|
||||
WorkQueue::with_none(body.basic_blocks().len());
|
||||
let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
|
||||
|
||||
if A::Direction::IS_FORWARD {
|
||||
for (bb, _) in traversal::reverse_postorder(body) {
|
||||
|
@ -108,12 +108,12 @@ where
|
||||
type Edge = CfgEdge;
|
||||
|
||||
fn nodes(&self) -> dot::Nodes<'_, Self::Node> {
|
||||
self.body.basic_blocks().indices().collect::<Vec<_>>().into()
|
||||
self.body.basic_blocks.indices().collect::<Vec<_>>().into()
|
||||
}
|
||||
|
||||
fn edges(&self) -> dot::Edges<'_, Self::Edge> {
|
||||
self.body
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.indices()
|
||||
.flat_map(|bb| dataflow_successors(self.body, bb))
|
||||
.collect::<Vec<_>>()
|
||||
|
@ -100,9 +100,9 @@ impl<D: Direction> MockAnalysis<'_, D> {
|
||||
|
||||
fn mock_entry_sets(&self) -> IndexVec<BasicBlock, BitSet<usize>> {
|
||||
let empty = self.bottom_value(self.body);
|
||||
let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks());
|
||||
let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks);
|
||||
|
||||
for (bb, _) in self.body.basic_blocks().iter_enumerated() {
|
||||
for (bb, _) in self.body.basic_blocks.iter_enumerated() {
|
||||
ret[bb] = self.mock_entry_set(bb);
|
||||
}
|
||||
|
||||
@ -169,7 +169,7 @@ impl<'tcx, D: Direction> AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> {
|
||||
const NAME: &'static str = "mock";
|
||||
|
||||
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
|
||||
BitSet::new_empty(Self::BASIC_BLOCK_OFFSET + body.basic_blocks().len())
|
||||
BitSet::new_empty(Self::BASIC_BLOCK_OFFSET + body.basic_blocks.len())
|
||||
}
|
||||
|
||||
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
|
||||
@ -271,9 +271,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
|
||||
cursor.allow_unreachable();
|
||||
|
||||
let every_target = || {
|
||||
body.basic_blocks()
|
||||
.iter_enumerated()
|
||||
.flat_map(|(bb, _)| SeekTarget::iter_in_block(body, bb))
|
||||
body.basic_blocks.iter_enumerated().flat_map(|(bb, _)| SeekTarget::iter_in_block(body, bb))
|
||||
};
|
||||
|
||||
let mut seek_to_target = |targ| {
|
||||
|
@ -243,7 +243,7 @@ pub(super) fn gather_moves<'tcx>(
|
||||
|
||||
builder.gather_args();
|
||||
|
||||
for (bb, block) in body.basic_blocks().iter_enumerated() {
|
||||
for (bb, block) in body.basic_blocks.iter_enumerated() {
|
||||
for (i, stmt) in block.statements.iter().enumerate() {
|
||||
let source = Location { block: bb, statement_index: i };
|
||||
builder.gather_statement(source, stmt);
|
||||
|
@ -217,7 +217,7 @@ where
|
||||
fn new(body: &Body<'_>) -> Self {
|
||||
LocationMap {
|
||||
map: body
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.iter()
|
||||
.map(|block| vec![T::default(); block.statements.len() + 1])
|
||||
.collect(),
|
||||
|
@ -101,7 +101,7 @@ pub fn sanity_check_via_rustc_peek<'tcx, A>(
|
||||
|
||||
let mut cursor = ResultsCursor::new(body, results);
|
||||
|
||||
let peek_calls = body.basic_blocks().iter_enumerated().filter_map(|(bb, block_data)| {
|
||||
let peek_calls = body.basic_blocks.iter_enumerated().filter_map(|(bb, block_data)| {
|
||||
PeekCall::from_terminator(tcx, block_data.terminator()).map(|call| (bb, block_data, call))
|
||||
});
|
||||
|
||||
|
@ -7,7 +7,7 @@ use rustc_middle::mir::{self, Local};
|
||||
pub fn always_storage_live_locals(body: &mir::Body<'_>) -> BitSet<Local> {
|
||||
let mut always_live_locals = BitSet::new_filled(body.local_decls.len());
|
||||
|
||||
for block in body.basic_blocks() {
|
||||
for block in &*body.basic_blocks {
|
||||
for statement in &block.statements {
|
||||
use mir::StatementKind::{StorageDead, StorageLive};
|
||||
if let StorageLive(l) | StorageDead(l) = statement.kind {
|
||||
|
@ -56,7 +56,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
|
||||
// example.
|
||||
let mut calls_to_terminate = Vec::new();
|
||||
let mut cleanups_to_remove = Vec::new();
|
||||
for (id, block) in body.basic_blocks().iter_enumerated() {
|
||||
for (id, block) in body.basic_blocks.iter_enumerated() {
|
||||
if block.is_cleanup {
|
||||
continue;
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ impl AddCallGuards {
|
||||
// We need a place to store the new blocks generated
|
||||
let mut new_blocks = Vec::new();
|
||||
|
||||
let cur_len = body.basic_blocks().len();
|
||||
let cur_len = body.basic_blocks.len();
|
||||
|
||||
for block in body.basic_blocks_mut() {
|
||||
match block.terminator {
|
||||
|
@ -55,7 +55,7 @@ fn add_moves_for_packed_drops_patch<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>)
|
||||
let mut patch = MirPatch::new(body);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
|
||||
for (bb, data) in body.basic_blocks().iter_enumerated() {
|
||||
for (bb, data) in body.basic_blocks.iter_enumerated() {
|
||||
let loc = Location { block: bb, statement_index: data.statements.len() };
|
||||
let terminator = data.terminator();
|
||||
|
||||
|
@ -66,7 +66,6 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
||||
// We need an `AllCallEdges` pass before we can do any work.
|
||||
super::add_call_guards::AllCallEdges.run_pass(tcx, body);
|
||||
|
||||
let (span, arg_count) = (body.span, body.arg_count);
|
||||
let basic_blocks = body.basic_blocks.as_mut();
|
||||
let local_decls = &body.local_decls;
|
||||
let needs_retag = |place: &Place<'tcx>| {
|
||||
@ -90,20 +89,18 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
||||
// PART 1
|
||||
// Retag arguments at the beginning of the start block.
|
||||
{
|
||||
// FIXME: Consider using just the span covering the function
|
||||
// argument declaration.
|
||||
let source_info = SourceInfo::outermost(span);
|
||||
// Gather all arguments, skip return value.
|
||||
let places = local_decls
|
||||
.iter_enumerated()
|
||||
.skip(1)
|
||||
.take(arg_count)
|
||||
.map(|(local, _)| Place::from(local))
|
||||
.filter(needs_retag);
|
||||
let places = local_decls.iter_enumerated().skip(1).take(body.arg_count).filter_map(
|
||||
|(local, decl)| {
|
||||
let place = Place::from(local);
|
||||
needs_retag(&place).then_some((place, decl.source_info))
|
||||
},
|
||||
);
|
||||
|
||||
// Emit their retags.
|
||||
basic_blocks[START_BLOCK].statements.splice(
|
||||
0..0,
|
||||
places.map(|place| Statement {
|
||||
places.map(|(place, source_info)| Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Retag(RetagKind::FnEntry, Box::new(place)),
|
||||
}),
|
||||
|
@ -61,14 +61,14 @@ impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> {
|
||||
let _: Option<_> = try {
|
||||
let target = terminator.kind.as_goto()?;
|
||||
// We only apply this optimization if the last statement is a const assignment
|
||||
let last_statement = self.body.basic_blocks()[location.block].statements.last()?;
|
||||
let last_statement = self.body.basic_blocks[location.block].statements.last()?;
|
||||
|
||||
if let (place, Rvalue::Use(Operand::Constant(_const))) =
|
||||
last_statement.kind.as_assign()?
|
||||
{
|
||||
// We found a constant being assigned to `place`.
|
||||
// Now check that the target of this Goto switches on this place.
|
||||
let target_bb = &self.body.basic_blocks()[target];
|
||||
let target_bb = &self.body.basic_blocks[target];
|
||||
|
||||
// The `StorageDead(..)` statement does not affect the functionality of mir.
|
||||
// We can move this part of the statement up to the predecessor.
|
||||
|
@ -131,7 +131,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
|
||||
|
||||
let dummy_body = &Body::new(
|
||||
body.source,
|
||||
body.basic_blocks().clone(),
|
||||
(*body.basic_blocks).clone(),
|
||||
body.source_scopes.clone(),
|
||||
body.local_decls.clone(),
|
||||
Default::default(),
|
||||
|
@ -105,7 +105,7 @@ impl<'tcx> MirLint<'tcx> for ConstProp {
|
||||
|
||||
let dummy_body = &Body::new(
|
||||
body.source,
|
||||
body.basic_blocks().clone(),
|
||||
(*body.basic_blocks).clone(),
|
||||
body.source_scopes.clone(),
|
||||
body.local_decls.clone(),
|
||||
Default::default(),
|
||||
@ -522,7 +522,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
||||
fn visit_body(&mut self, body: &Body<'tcx>) {
|
||||
for (bb, data) in body.basic_blocks().iter_enumerated() {
|
||||
for (bb, data) in body.basic_blocks.iter_enumerated() {
|
||||
self.visit_basic_block_data(bb, data);
|
||||
}
|
||||
}
|
||||
|
@ -713,7 +713,7 @@ impl<
|
||||
|
||||
ShortCircuitPreorder {
|
||||
body,
|
||||
visited: BitSet::new_empty(body.basic_blocks().len()),
|
||||
visited: BitSet::new_empty(body.basic_blocks.len()),
|
||||
worklist,
|
||||
filtered_successors,
|
||||
}
|
||||
@ -747,7 +747,7 @@ impl<
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let size = self.body.basic_blocks().len() - self.visited.count();
|
||||
let size = self.body.basic_blocks.len() - self.visited.count();
|
||||
(size, Some(size))
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
|
||||
return;
|
||||
}
|
||||
|
||||
match mir_body.basic_blocks()[mir::START_BLOCK].terminator().kind {
|
||||
match mir_body.basic_blocks[mir::START_BLOCK].terminator().kind {
|
||||
TerminatorKind::Unreachable => {
|
||||
trace!("InstrumentCoverage skipped for unreachable `START_BLOCK`");
|
||||
return;
|
||||
|
@ -84,7 +84,7 @@ impl CoverageVisitor {
|
||||
}
|
||||
|
||||
fn visit_body(&mut self, body: &Body<'_>) {
|
||||
for bb_data in body.basic_blocks().iter() {
|
||||
for bb_data in body.basic_blocks.iter() {
|
||||
for statement in bb_data.statements.iter() {
|
||||
if let StatementKind::Coverage(box ref coverage) = statement.kind {
|
||||
if is_inlined(body, statement) {
|
||||
@ -138,7 +138,7 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) ->
|
||||
|
||||
fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> {
|
||||
let body = mir_body(tcx, def_id);
|
||||
body.basic_blocks()
|
||||
body.basic_blocks
|
||||
.iter()
|
||||
.flat_map(|data| {
|
||||
data.statements.iter().filter_map(|statement| match statement.kind {
|
||||
|
@ -176,7 +176,7 @@ fn debug_basic_blocks<'tcx>(mir_body: &Body<'tcx>) -> String {
|
||||
format!(
|
||||
"{:?}",
|
||||
mir_body
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.iter_enumerated()
|
||||
.map(|(bb, data)| {
|
||||
let term = &data.terminator();
|
||||
@ -213,7 +213,7 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) {
|
||||
"digraph {} {{\n{}\n}}",
|
||||
name,
|
||||
mir_body
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.iter_enumerated()
|
||||
.map(|(bb, data)| {
|
||||
format!(
|
||||
@ -653,7 +653,7 @@ fn test_traverse_coverage_with_loops() {
|
||||
|
||||
fn synthesize_body_span_from_terminators(mir_body: &Body<'_>) -> Span {
|
||||
let mut some_span: Option<Span> = None;
|
||||
for (_, data) in mir_body.basic_blocks().iter_enumerated() {
|
||||
for (_, data) in mir_body.basic_blocks.iter_enumerated() {
|
||||
let term_span = data.terminator().source_info.span;
|
||||
if let Some(span) = some_span.as_mut() {
|
||||
*span = span.to(term_span);
|
||||
|
@ -58,7 +58,7 @@ fn find_duplicates(body: &Body<'_>) -> FxHashMap<BasicBlock, BasicBlock> {
|
||||
let mut duplicates = FxHashMap::default();
|
||||
|
||||
let bbs_to_go_through =
|
||||
body.basic_blocks().iter_enumerated().filter(|(_, bbd)| !bbd.is_cleanup).count();
|
||||
body.basic_blocks.iter_enumerated().filter(|(_, bbd)| !bbd.is_cleanup).count();
|
||||
|
||||
let mut same_hashes =
|
||||
FxHashMap::with_capacity_and_hasher(bbs_to_go_through, Default::default());
|
||||
@ -71,8 +71,7 @@ fn find_duplicates(body: &Body<'_>) -> FxHashMap<BasicBlock, BasicBlock> {
|
||||
// When we see bb1, we see that it is a duplicate of bb3, and therefore insert it in the duplicates list
|
||||
// with replacement bb3.
|
||||
// When the duplicates are removed, we will end up with only bb3.
|
||||
for (bb, bbd) in body.basic_blocks().iter_enumerated().rev().filter(|(_, bbd)| !bbd.is_cleanup)
|
||||
{
|
||||
for (bb, bbd) in body.basic_blocks.iter_enumerated().rev().filter(|(_, bbd)| !bbd.is_cleanup) {
|
||||
// Basic blocks can get really big, so to avoid checking for duplicates in basic blocks
|
||||
// that are unlikely to have duplicates, we stop early. The early bail number has been
|
||||
// found experimentally by eprintln while compiling the crates in the rustc-perf suite.
|
||||
|
@ -150,7 +150,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
|
||||
def_id,
|
||||
body.local_decls.len(),
|
||||
relevant,
|
||||
body.basic_blocks().len()
|
||||
body.basic_blocks.len()
|
||||
);
|
||||
if relevant > MAX_LOCALS {
|
||||
warn!(
|
||||
@ -159,11 +159,11 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
|
||||
);
|
||||
return;
|
||||
}
|
||||
if body.basic_blocks().len() > MAX_BLOCKS {
|
||||
if body.basic_blocks.len() > MAX_BLOCKS {
|
||||
warn!(
|
||||
"too many blocks in {:?} ({}, max is {}), not optimizing",
|
||||
def_id,
|
||||
body.basic_blocks().len(),
|
||||
body.basic_blocks.len(),
|
||||
MAX_BLOCKS
|
||||
);
|
||||
return;
|
||||
|
@ -104,8 +104,8 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
|
||||
let mut should_cleanup = false;
|
||||
|
||||
// Also consider newly generated bbs in the same pass
|
||||
for i in 0..body.basic_blocks().len() {
|
||||
let bbs = body.basic_blocks();
|
||||
for i in 0..body.basic_blocks.len() {
|
||||
let bbs = &*body.basic_blocks;
|
||||
let parent = BasicBlock::from_usize(i);
|
||||
let Some(opt_data) = evaluate_candidate(tcx, body, parent) else {
|
||||
continue
|
||||
@ -316,7 +316,7 @@ fn evaluate_candidate<'tcx>(
|
||||
body: &Body<'tcx>,
|
||||
parent: BasicBlock,
|
||||
) -> Option<OptimizationData<'tcx>> {
|
||||
let bbs = body.basic_blocks();
|
||||
let bbs = &body.basic_blocks;
|
||||
let TerminatorKind::SwitchInt {
|
||||
targets,
|
||||
switch_ty: parent_ty,
|
||||
|
@ -89,13 +89,13 @@ fn find_dead_unwinds<'tcx>(
|
||||
debug!("find_dead_unwinds({:?})", body.span);
|
||||
// We only need to do this pass once, because unwind edges can only
|
||||
// reach cleanup blocks, which can't have unwind edges themselves.
|
||||
let mut dead_unwinds = BitSet::new_empty(body.basic_blocks().len());
|
||||
let mut dead_unwinds = BitSet::new_empty(body.basic_blocks.len());
|
||||
let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env)
|
||||
.into_engine(tcx, body)
|
||||
.pass_name("find_dead_unwinds")
|
||||
.iterate_to_fixpoint()
|
||||
.into_results_cursor(body);
|
||||
for (bb, bb_data) in body.basic_blocks().iter_enumerated() {
|
||||
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
|
||||
let place = match bb_data.terminator().kind {
|
||||
TerminatorKind::Drop { ref place, unwind: Some(_), .. }
|
||||
| TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => {
|
||||
@ -303,7 +303,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
}
|
||||
|
||||
fn collect_drop_flags(&mut self) {
|
||||
for (bb, data) in self.body.basic_blocks().iter_enumerated() {
|
||||
for (bb, data) in self.body.basic_blocks.iter_enumerated() {
|
||||
let terminator = data.terminator();
|
||||
let place = match terminator.kind {
|
||||
TerminatorKind::Drop { ref place, .. }
|
||||
@ -358,7 +358,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
}
|
||||
|
||||
fn elaborate_drops(&mut self) {
|
||||
for (bb, data) in self.body.basic_blocks().iter_enumerated() {
|
||||
for (bb, data) in self.body.basic_blocks.iter_enumerated() {
|
||||
let loc = Location { block: bb, statement_index: data.statements.len() };
|
||||
let terminator = data.terminator();
|
||||
|
||||
@ -515,7 +515,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
}
|
||||
|
||||
fn drop_flags_for_fn_rets(&mut self) {
|
||||
for (bb, data) in self.body.basic_blocks().iter_enumerated() {
|
||||
for (bb, data) in self.body.basic_blocks.iter_enumerated() {
|
||||
if let TerminatorKind::Call {
|
||||
destination, target: Some(tgt), cleanup: Some(_), ..
|
||||
} = data.terminator().kind
|
||||
@ -550,7 +550,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
// drop flags by themselves, to avoid the drop flags being
|
||||
// clobbered before they are read.
|
||||
|
||||
for (bb, data) in self.body.basic_blocks().iter_enumerated() {
|
||||
for (bb, data) in self.body.basic_blocks.iter_enumerated() {
|
||||
debug!("drop_flags_for_locs({:?})", data);
|
||||
for i in 0..(data.statements.len() + 1) {
|
||||
debug!("drop_flag_for_locs: stmt {}", i);
|
||||
|
@ -65,7 +65,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
|
||||
|
||||
let mut tainted = false;
|
||||
|
||||
for block in body.basic_blocks() {
|
||||
for block in body.basic_blocks.iter() {
|
||||
if block.is_cleanup {
|
||||
continue;
|
||||
}
|
||||
|
@ -490,12 +490,12 @@ fn locals_live_across_suspend_points<'tcx>(
|
||||
.iterate_to_fixpoint()
|
||||
.into_results_cursor(body_ref);
|
||||
|
||||
let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks());
|
||||
let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks);
|
||||
let mut live_locals_at_suspension_points = Vec::new();
|
||||
let mut source_info_at_suspension_points = Vec::new();
|
||||
let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len());
|
||||
|
||||
for (block, data) in body.basic_blocks().iter_enumerated() {
|
||||
for (block, data) in body.basic_blocks.iter_enumerated() {
|
||||
if let TerminatorKind::Yield { .. } = data.terminator().kind {
|
||||
let loc = Location { block, statement_index: data.statements.len() };
|
||||
|
||||
@ -704,7 +704,7 @@ impl<'mir, 'tcx> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx>
|
||||
impl StorageConflictVisitor<'_, '_, '_> {
|
||||
fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) {
|
||||
// Ignore unreachable blocks.
|
||||
if self.body.basic_blocks()[loc.block].terminator().kind == TerminatorKind::Unreachable {
|
||||
if self.body.basic_blocks[loc.block].terminator().kind == TerminatorKind::Unreachable {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -886,7 +886,7 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
|
||||
let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, param_env };
|
||||
|
||||
for (block, block_data) in body.basic_blocks().iter_enumerated() {
|
||||
for (block, block_data) in body.basic_blocks.iter_enumerated() {
|
||||
let (target, unwind, source_info) = match block_data.terminator() {
|
||||
Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => {
|
||||
if let Some(local) = place.as_local() {
|
||||
@ -991,7 +991,7 @@ fn insert_panic_block<'tcx>(
|
||||
body: &mut Body<'tcx>,
|
||||
message: AssertMessage<'tcx>,
|
||||
) -> BasicBlock {
|
||||
let assert_block = BasicBlock::new(body.basic_blocks().len());
|
||||
let assert_block = BasicBlock::new(body.basic_blocks.len());
|
||||
let term = TerminatorKind::Assert {
|
||||
cond: Operand::Constant(Box::new(Constant {
|
||||
span: body.span,
|
||||
@ -1021,7 +1021,7 @@ fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ty::ParamEn
|
||||
}
|
||||
|
||||
// If there's a return terminator the function may return.
|
||||
for block in body.basic_blocks() {
|
||||
for block in body.basic_blocks.iter() {
|
||||
if let TerminatorKind::Return = block.terminator().kind {
|
||||
return true;
|
||||
}
|
||||
@ -1038,7 +1038,7 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
|
||||
}
|
||||
|
||||
// Unwinds can only start at certain terminators.
|
||||
for block in body.basic_blocks() {
|
||||
for block in body.basic_blocks.iter() {
|
||||
match block.terminator().kind {
|
||||
// These never unwind.
|
||||
TerminatorKind::Goto { .. }
|
||||
|
@ -95,7 +95,7 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
|
||||
history: Vec::new(),
|
||||
changed: false,
|
||||
};
|
||||
let blocks = BasicBlock::new(0)..body.basic_blocks().next_index();
|
||||
let blocks = BasicBlock::new(0)..body.basic_blocks.next_index();
|
||||
this.process_blocks(body, blocks);
|
||||
this.changed
|
||||
}
|
||||
@ -217,9 +217,9 @@ impl<'tcx> Inliner<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
let old_blocks = caller_body.basic_blocks().next_index();
|
||||
let old_blocks = caller_body.basic_blocks.next_index();
|
||||
self.inline_call(caller_body, &callsite, callee_body);
|
||||
let new_blocks = old_blocks..caller_body.basic_blocks().next_index();
|
||||
let new_blocks = old_blocks..caller_body.basic_blocks.next_index();
|
||||
|
||||
Ok(new_blocks)
|
||||
}
|
||||
@ -409,14 +409,14 @@ impl<'tcx> Inliner<'tcx> {
|
||||
// Give a bonus functions with a small number of blocks,
|
||||
// We normally have two or three blocks for even
|
||||
// very small functions.
|
||||
if callee_body.basic_blocks().len() <= 3 {
|
||||
if callee_body.basic_blocks.len() <= 3 {
|
||||
threshold += threshold / 4;
|
||||
}
|
||||
debug!(" final inline threshold = {}", threshold);
|
||||
|
||||
// FIXME: Give a bonus to functions with only a single caller
|
||||
let diverges = matches!(
|
||||
callee_body.basic_blocks()[START_BLOCK].terminator().kind,
|
||||
callee_body.basic_blocks[START_BLOCK].terminator().kind,
|
||||
TerminatorKind::Unreachable | TerminatorKind::Call { target: None, .. }
|
||||
);
|
||||
if diverges && !matches!(callee_attrs.inline, InlineAttr::Always) {
|
||||
@ -434,13 +434,13 @@ impl<'tcx> Inliner<'tcx> {
|
||||
|
||||
// Traverse the MIR manually so we can account for the effects of inlining on the CFG.
|
||||
let mut work_list = vec![START_BLOCK];
|
||||
let mut visited = BitSet::new_empty(callee_body.basic_blocks().len());
|
||||
let mut visited = BitSet::new_empty(callee_body.basic_blocks.len());
|
||||
while let Some(bb) = work_list.pop() {
|
||||
if !visited.insert(bb.index()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let blk = &callee_body.basic_blocks()[bb];
|
||||
let blk = &callee_body.basic_blocks[bb];
|
||||
checker.visit_basic_block_data(bb, blk);
|
||||
|
||||
let term = blk.terminator();
|
||||
@ -541,7 +541,7 @@ impl<'tcx> Inliner<'tcx> {
|
||||
args: &args,
|
||||
new_locals: Local::new(caller_body.local_decls.len())..,
|
||||
new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
|
||||
new_blocks: BasicBlock::new(caller_body.basic_blocks().len())..,
|
||||
new_blocks: BasicBlock::new(caller_body.basic_blocks.len())..,
|
||||
destination: dest,
|
||||
callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
|
||||
callsite,
|
||||
|
@ -153,7 +153,7 @@ pub(crate) fn mir_inliner_callees<'tcx>(
|
||||
_ => tcx.instance_mir(instance),
|
||||
};
|
||||
let mut calls = FxIndexSet::default();
|
||||
for bb_data in body.basic_blocks() {
|
||||
for bb_data in body.basic_blocks.iter() {
|
||||
let terminator = bb_data.terminator();
|
||||
if let TerminatorKind::Call { func, .. } = &terminator.kind {
|
||||
let ty = func.ty(&body.local_decls, tcx);
|
||||
|
@ -15,7 +15,7 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
|
||||
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
// find basic blocks with no statement and a return terminator
|
||||
let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len());
|
||||
let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks.len());
|
||||
let def_id = body.source.def_id();
|
||||
let bbs = body.basic_blocks_mut();
|
||||
for idx in bbs.indices() {
|
||||
|
@ -21,10 +21,10 @@ impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
|
||||
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
// early returns for edge cases of highly unrolled functions
|
||||
if body.basic_blocks().len() > MAX_NUM_BLOCKS {
|
||||
if body.basic_blocks.len() > MAX_NUM_BLOCKS {
|
||||
return;
|
||||
}
|
||||
if body.local_decls().len() > MAX_NUM_LOCALS {
|
||||
if body.local_decls.len() > MAX_NUM_LOCALS {
|
||||
return;
|
||||
}
|
||||
normalize_array_len_calls(tcx, body)
|
||||
|
@ -89,7 +89,7 @@ fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option<Local> {
|
||||
}
|
||||
|
||||
let mut copied_to_return_place = None;
|
||||
for block in body.basic_blocks().indices() {
|
||||
for block in body.basic_blocks.indices() {
|
||||
// Look for blocks with a `Return` terminator.
|
||||
if !matches!(body[block].terminator().kind, mir::TerminatorKind::Return) {
|
||||
continue;
|
||||
@ -122,7 +122,7 @@ fn find_local_assigned_to_return_place(
|
||||
body: &mut mir::Body<'_>,
|
||||
) -> Option<Local> {
|
||||
let mut block = start;
|
||||
let mut seen = HybridBitSet::new_empty(body.basic_blocks().len());
|
||||
let mut seen = HybridBitSet::new_empty(body.basic_blocks.len());
|
||||
|
||||
// Iterate as long as `block` has exactly one predecessor that we have not yet visited.
|
||||
while seen.insert(block) {
|
||||
|
@ -94,7 +94,7 @@ impl RemoveNoopLandingPads {
|
||||
|
||||
let mut jumps_folded = 0;
|
||||
let mut landing_pads_removed = 0;
|
||||
let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks().len());
|
||||
let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks.len());
|
||||
|
||||
// This is a post-order traversal, so that if A post-dominates B
|
||||
// then A will be visited before B.
|
||||
|
@ -35,7 +35,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
|
||||
.into_results_cursor(body);
|
||||
|
||||
let mut to_remove = vec![];
|
||||
for (bb, block) in body.basic_blocks().iter_enumerated() {
|
||||
for (bb, block) in body.basic_blocks.iter_enumerated() {
|
||||
let terminator = block.terminator();
|
||||
let (TerminatorKind::Drop { place, .. } | TerminatorKind::DropAndReplace { place, .. })
|
||||
= &terminator.kind
|
||||
|
@ -62,7 +62,7 @@ impl<'tcx> MirPass<'tcx> for SeparateConstSwitch {
|
||||
pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
||||
let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new();
|
||||
let predecessors = body.basic_blocks.predecessors();
|
||||
'block_iter: for (block_id, block) in body.basic_blocks().iter_enumerated() {
|
||||
'block_iter: for (block_id, block) in body.basic_blocks.iter_enumerated() {
|
||||
if let TerminatorKind::SwitchInt {
|
||||
discr: Operand::Copy(switch_place) | Operand::Move(switch_place),
|
||||
..
|
||||
@ -90,7 +90,7 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
||||
|
||||
let mut predecessors_left = predecessors[block_id].len();
|
||||
'predec_iter: for predecessor_id in predecessors[block_id].iter().copied() {
|
||||
let predecessor = &body.basic_blocks()[predecessor_id];
|
||||
let predecessor = &body.basic_blocks[predecessor_id];
|
||||
|
||||
// First we make sure the predecessor jumps
|
||||
// in a reasonable way
|
||||
|
@ -74,7 +74,7 @@ pub struct CfgSimplifier<'a, 'tcx> {
|
||||
|
||||
impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
|
||||
pub fn new(body: &'a mut Body<'tcx>) -> Self {
|
||||
let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks());
|
||||
let mut pred_count = IndexVec::from_elem(0u32, &body.basic_blocks);
|
||||
|
||||
// we can't use mir.predecessors() here because that counts
|
||||
// dead blocks, which we don't want to.
|
||||
@ -263,7 +263,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
|
||||
|
||||
pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let reachable = traversal::reachable_as_bitset(body);
|
||||
let num_blocks = body.basic_blocks().len();
|
||||
let num_blocks = body.basic_blocks.len();
|
||||
if num_blocks == reachable.count() {
|
||||
return;
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ struct OptimizationFinder<'a, 'tcx> {
|
||||
impl<'tcx> OptimizationFinder<'_, 'tcx> {
|
||||
fn find_optimizations(&self) -> Vec<OptimizationInfo<'tcx>> {
|
||||
self.body
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.iter_enumerated()
|
||||
.filter_map(|(bb_idx, bb)| {
|
||||
// find switch
|
||||
|
@ -596,7 +596,7 @@ struct SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
|
||||
impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> {
|
||||
fn find(&self) -> Vec<SimplifyBranchSameOptimization> {
|
||||
self.body
|
||||
.basic_blocks()
|
||||
.basic_blocks
|
||||
.iter_enumerated()
|
||||
.filter_map(|(bb_idx, bb)| {
|
||||
let (discr_switched_on, targets_and_values) = match &bb.terminator().kind {
|
||||
@ -632,7 +632,7 @@ impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> {
|
||||
|
||||
let mut iter_bbs_reachable = targets_and_values
|
||||
.iter()
|
||||
.map(|target_and_value| (target_and_value, &self.body.basic_blocks()[target_and_value.target]))
|
||||
.map(|target_and_value| (target_and_value, &self.body.basic_blocks[target_and_value.target]))
|
||||
.filter(|(_, bb)| {
|
||||
// Reaching `unreachable` is UB so assume it doesn't happen.
|
||||
bb.terminator().kind != TerminatorKind::Unreachable
|
||||
|
@ -79,7 +79,7 @@ fn ensure_otherwise_unreachable<'tcx>(
|
||||
targets: &SwitchTargets,
|
||||
) -> Option<BasicBlockData<'tcx>> {
|
||||
let otherwise = targets.otherwise();
|
||||
let bb = &body.basic_blocks()[otherwise];
|
||||
let bb = &body.basic_blocks[otherwise];
|
||||
if bb.terminator().kind == TerminatorKind::Unreachable
|
||||
&& bb.statements.iter().all(|s| matches!(&s.kind, StatementKind::StorageDead(_)))
|
||||
{
|
||||
@ -102,10 +102,10 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
trace!("UninhabitedEnumBranching starting for {:?}", body.source);
|
||||
|
||||
for bb in body.basic_blocks().indices() {
|
||||
for bb in body.basic_blocks.indices() {
|
||||
trace!("processing block {:?}", bb);
|
||||
|
||||
let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) else {
|
||||
let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks[bb], tcx, body) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
@ -481,7 +481,7 @@ fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSe
|
||||
continue;
|
||||
}
|
||||
let body = tcx.instance_mir(instance.def);
|
||||
for block in body.basic_blocks() {
|
||||
for block in body.basic_blocks.iter() {
|
||||
for statement in &block.statements {
|
||||
let mir::StatementKind::Coverage(_) = statement.kind else { continue };
|
||||
let scope = statement.source_info.scope;
|
||||
|
@ -28,7 +28,7 @@ pub struct IgnoredInlineAttrFnProto;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes::inline_ignored_constants)]
|
||||
#[warn_]
|
||||
#[warning]
|
||||
#[note]
|
||||
pub struct IgnoredInlineAttrConstants;
|
||||
|
||||
@ -347,7 +347,7 @@ pub struct MustNotSuspend {
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes::cold)]
|
||||
#[warn_]
|
||||
#[warning]
|
||||
pub struct Cold {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
@ -355,7 +355,7 @@ pub struct Cold {
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes::link)]
|
||||
#[warn_]
|
||||
#[warning]
|
||||
pub struct Link {
|
||||
#[label]
|
||||
pub span: Option<Span>,
|
||||
@ -363,7 +363,7 @@ pub struct Link {
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes::link_name)]
|
||||
#[warn_]
|
||||
#[warning]
|
||||
pub struct LinkName<'a> {
|
||||
#[help]
|
||||
pub attr_span: Option<Span>,
|
||||
@ -449,7 +449,7 @@ pub struct RustcDirtyClean {
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes::link_section)]
|
||||
#[warn_]
|
||||
#[warning]
|
||||
pub struct LinkSection {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
@ -457,7 +457,7 @@ pub struct LinkSection {
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes::no_mangle_foreign)]
|
||||
#[warn_]
|
||||
#[warning]
|
||||
#[note]
|
||||
pub struct NoMangleForeign {
|
||||
#[label]
|
||||
@ -469,7 +469,7 @@ pub struct NoMangleForeign {
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes::no_mangle)]
|
||||
#[warn_]
|
||||
#[warning]
|
||||
pub struct NoMangle {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
@ -617,7 +617,7 @@ pub struct UnusedDuplicate {
|
||||
pub this: Span,
|
||||
#[note]
|
||||
pub other: Span,
|
||||
#[warn_]
|
||||
#[warning]
|
||||
pub warning: Option<()>,
|
||||
}
|
||||
|
||||
|
@ -1506,13 +1506,28 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
.emit();
|
||||
}
|
||||
FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => {
|
||||
self.report_mismatched_consts(
|
||||
let mut diag = self.report_mismatched_consts(
|
||||
&error.obligation.cause,
|
||||
expected_found.expected,
|
||||
expected_found.found,
|
||||
err.clone(),
|
||||
)
|
||||
.emit();
|
||||
);
|
||||
let code = error.obligation.cause.code().peel_derives().peel_match_impls();
|
||||
if let ObligationCauseCode::BindingObligation(..)
|
||||
| ObligationCauseCode::ItemObligation(..)
|
||||
| ObligationCauseCode::ExprBindingObligation(..)
|
||||
| ObligationCauseCode::ExprItemObligation(..) = code
|
||||
{
|
||||
self.note_obligation_cause_code(
|
||||
&mut diag,
|
||||
&error.obligation.predicate,
|
||||
error.obligation.param_env,
|
||||
code,
|
||||
&mut vec![],
|
||||
&mut Default::default(),
|
||||
);
|
||||
}
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -348,7 +348,7 @@ fn instance_def_size_estimate<'tcx>(
|
||||
match instance_def {
|
||||
InstanceDef::Item(..) | InstanceDef::DropGlue(..) => {
|
||||
let mir = tcx.instance_mir(instance_def);
|
||||
mir.basic_blocks().iter().map(|bb| bb.statements.len() + 1).sum()
|
||||
mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum()
|
||||
}
|
||||
// Estimate the size of other compiler-generated shims to be 1.
|
||||
_ => 1,
|
||||
|
@ -39,8 +39,8 @@ struct Parser<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
fn new(input: &'a str) -> Parser<'a> {
|
||||
Parser { state: input.as_bytes() }
|
||||
fn new(input: &'a [u8]) -> Parser<'a> {
|
||||
Parser { state: input }
|
||||
}
|
||||
|
||||
/// Run a parser, and restore the pre-parse state if it fails.
|
||||
@ -273,11 +273,54 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl IpAddr {
|
||||
/// Parse an IP address from a slice of bytes.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(addr_parse_ascii)]
|
||||
///
|
||||
/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
///
|
||||
/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
|
||||
/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
|
||||
///
|
||||
/// assert_eq!(IpAddr::parse_ascii(b"127.0.0.1"), Ok(localhost_v4));
|
||||
/// assert_eq!(IpAddr::parse_ascii(b"::1"), Ok(localhost_v6));
|
||||
/// ```
|
||||
#[unstable(feature = "addr_parse_ascii", issue = "101035")]
|
||||
pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
|
||||
Parser::new(b).parse_with(|p| p.read_ip_addr(), AddrKind::Ip)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "ip_addr", since = "1.7.0")]
|
||||
impl FromStr for IpAddr {
|
||||
type Err = AddrParseError;
|
||||
fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
|
||||
Parser::new(s).parse_with(|p| p.read_ip_addr(), AddrKind::Ip)
|
||||
Self::parse_ascii(s.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Ipv4Addr {
|
||||
/// Parse an IPv4 address from a slice of bytes.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(addr_parse_ascii)]
|
||||
///
|
||||
/// use std::net::Ipv4Addr;
|
||||
///
|
||||
/// let localhost = Ipv4Addr::new(127, 0, 0, 1);
|
||||
///
|
||||
/// assert_eq!(Ipv4Addr::parse_ascii(b"127.0.0.1"), Ok(localhost));
|
||||
/// ```
|
||||
#[unstable(feature = "addr_parse_ascii", issue = "101035")]
|
||||
pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
|
||||
// don't try to parse if too long
|
||||
if b.len() > 15 {
|
||||
Err(AddrParseError(AddrKind::Ipv4))
|
||||
} else {
|
||||
Parser::new(b).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,12 +328,25 @@ impl FromStr for IpAddr {
|
||||
impl FromStr for Ipv4Addr {
|
||||
type Err = AddrParseError;
|
||||
fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
|
||||
// don't try to parse if too long
|
||||
if s.len() > 15 {
|
||||
Err(AddrParseError(AddrKind::Ipv4))
|
||||
} else {
|
||||
Parser::new(s).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
|
||||
}
|
||||
Self::parse_ascii(s.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Ipv6Addr {
|
||||
/// Parse an IPv6 address from a slice of bytes.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(addr_parse_ascii)]
|
||||
///
|
||||
/// use std::net::Ipv6Addr;
|
||||
///
|
||||
/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
|
||||
///
|
||||
/// assert_eq!(Ipv6Addr::parse_ascii(b"::1"), Ok(localhost));
|
||||
/// ```
|
||||
#[unstable(feature = "addr_parse_ascii", issue = "101035")]
|
||||
pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
|
||||
Parser::new(b).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,7 +354,25 @@ impl FromStr for Ipv4Addr {
|
||||
impl FromStr for Ipv6Addr {
|
||||
type Err = AddrParseError;
|
||||
fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
|
||||
Parser::new(s).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
|
||||
Self::parse_ascii(s.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl SocketAddrV4 {
|
||||
/// Parse an IPv4 socket address from a slice of bytes.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(addr_parse_ascii)]
|
||||
///
|
||||
/// use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
///
|
||||
/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
|
||||
///
|
||||
/// assert_eq!(SocketAddrV4::parse_ascii(b"127.0.0.1:8080"), Ok(socket));
|
||||
/// ```
|
||||
#[unstable(feature = "addr_parse_ascii", issue = "101035")]
|
||||
pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
|
||||
Parser::new(b).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4)
|
||||
}
|
||||
}
|
||||
|
||||
@ -306,7 +380,25 @@ impl FromStr for Ipv6Addr {
|
||||
impl FromStr for SocketAddrV4 {
|
||||
type Err = AddrParseError;
|
||||
fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
|
||||
Parser::new(s).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4)
|
||||
Self::parse_ascii(s.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl SocketAddrV6 {
|
||||
/// Parse an IPv6 socket address from a slice of bytes.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(addr_parse_ascii)]
|
||||
///
|
||||
/// use std::net::{Ipv6Addr, SocketAddrV6};
|
||||
///
|
||||
/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
|
||||
///
|
||||
/// assert_eq!(SocketAddrV6::parse_ascii(b"[2001:db8::1]:8080"), Ok(socket));
|
||||
/// ```
|
||||
#[unstable(feature = "addr_parse_ascii", issue = "101035")]
|
||||
pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
|
||||
Parser::new(b).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6)
|
||||
}
|
||||
}
|
||||
|
||||
@ -314,7 +406,27 @@ impl FromStr for SocketAddrV4 {
|
||||
impl FromStr for SocketAddrV6 {
|
||||
type Err = AddrParseError;
|
||||
fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
|
||||
Parser::new(s).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6)
|
||||
Self::parse_ascii(s.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl SocketAddr {
|
||||
/// Parse a socket address from a slice of bytes.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(addr_parse_ascii)]
|
||||
///
|
||||
/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
///
|
||||
/// let socket_v4 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
|
||||
/// let socket_v6 = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 8080);
|
||||
///
|
||||
/// assert_eq!(SocketAddr::parse_ascii(b"127.0.0.1:8080"), Ok(socket_v4));
|
||||
/// assert_eq!(SocketAddr::parse_ascii(b"[::1]:8080"), Ok(socket_v6));
|
||||
/// ```
|
||||
#[unstable(feature = "addr_parse_ascii", issue = "101035")]
|
||||
pub fn parse_ascii(b: &[u8]) -> Result<Self, AddrParseError> {
|
||||
Parser::new(b).parse_with(|p| p.read_socket_addr(), AddrKind::Socket)
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,7 +434,7 @@ impl FromStr for SocketAddrV6 {
|
||||
impl FromStr for SocketAddr {
|
||||
type Err = AddrParseError;
|
||||
fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
|
||||
Parser::new(s).parse_with(|p| p.read_socket_addr(), AddrKind::Socket)
|
||||
Self::parse_ascii(s.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -838,6 +838,31 @@ impl UnixDatagram {
|
||||
self.0.passcred()
|
||||
}
|
||||
|
||||
/// Set the id of the socket for network filtering purpose
|
||||
///
|
||||
#[cfg_attr(
|
||||
any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"),
|
||||
doc = "```no_run"
|
||||
)]
|
||||
#[cfg_attr(
|
||||
not(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd")),
|
||||
doc = "```ignore"
|
||||
)]
|
||||
/// #![feature(unix_set_mark)]
|
||||
/// use std::os::unix::net::UnixDatagram;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let sock = UnixDatagram::unbound()?;
|
||||
/// sock.set_mark(32)?;
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(any(doc, target_os = "linux", target_os = "freebsd", target_os = "openbsd",))]
|
||||
#[unstable(feature = "unix_set_mark", issue = "96467")]
|
||||
pub fn set_mark(&self, mark: u32) -> io::Result<()> {
|
||||
self.0.set_mark(mark)
|
||||
}
|
||||
|
||||
/// Returns the value of the `SO_ERROR` option.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -427,6 +427,31 @@ impl UnixStream {
|
||||
self.0.passcred()
|
||||
}
|
||||
|
||||
/// Set the id of the socket for network filtering purpose
|
||||
///
|
||||
#[cfg_attr(
|
||||
any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"),
|
||||
doc = "```no_run"
|
||||
)]
|
||||
#[cfg_attr(
|
||||
not(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd")),
|
||||
doc = "```ignore"
|
||||
)]
|
||||
/// #![feature(unix_set_mark)]
|
||||
/// use std::os::unix::net::UnixStream;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let sock = UnixStream::connect("/tmp/sock")?;
|
||||
/// sock.set_mark(32)?;
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(any(doc, target_os = "linux", target_os = "freebsd", target_os = "openbsd",))]
|
||||
#[unstable(feature = "unix_set_mark", issue = "96467")]
|
||||
pub fn set_mark(&self, mark: u32) -> io::Result<()> {
|
||||
self.0.set_mark(mark)
|
||||
}
|
||||
|
||||
/// Returns the value of the `SO_ERROR` option.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -438,6 +438,17 @@ impl Socket {
|
||||
self.0.set_nonblocking(nonblocking)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
|
||||
pub fn set_mark(&self, mark: u32) -> io::Result<()> {
|
||||
#[cfg(target_os = "linux")]
|
||||
let option = libc::SO_MARK;
|
||||
#[cfg(target_os = "freebsd")]
|
||||
let option = libc::SO_USER_COOKIE;
|
||||
#[cfg(target_os = "openbsd")]
|
||||
let option = libc::SO_RTABLE;
|
||||
setsockopt(self, libc::SOL_SOCKET, option, mark as libc::c_int)
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
|
||||
if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
|
||||
|
@ -24,8 +24,6 @@ use crate::clean::{
|
||||
use crate::core::DocContext;
|
||||
use crate::formats::item_type::ItemType;
|
||||
|
||||
type Attrs<'hir> = &'hir [ast::Attribute];
|
||||
|
||||
/// Attempt to inline a definition into this AST.
|
||||
///
|
||||
/// This function will fetch the definition specified, and if it is
|
||||
@ -46,7 +44,7 @@ pub(crate) fn try_inline(
|
||||
import_def_id: Option<DefId>,
|
||||
res: Res,
|
||||
name: Symbol,
|
||||
attrs: Option<Attrs<'_>>,
|
||||
attrs: Option<&[ast::Attribute]>,
|
||||
visited: &mut FxHashSet<DefId>,
|
||||
) -> Option<Vec<clean::Item>> {
|
||||
let did = res.opt_def_id()?;
|
||||
@ -172,7 +170,7 @@ pub(crate) fn try_inline_glob(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> {
|
||||
pub(crate) fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> &'hir [ast::Attribute] {
|
||||
cx.tcx.get_attrs_unchecked(did)
|
||||
}
|
||||
|
||||
@ -287,7 +285,7 @@ pub(crate) fn build_impls(
|
||||
cx: &mut DocContext<'_>,
|
||||
parent_module: Option<DefId>,
|
||||
did: DefId,
|
||||
attrs: Option<Attrs<'_>>,
|
||||
attrs: Option<&[ast::Attribute]>,
|
||||
ret: &mut Vec<clean::Item>,
|
||||
) {
|
||||
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls");
|
||||
@ -303,8 +301,8 @@ pub(crate) fn build_impls(
|
||||
pub(crate) fn merge_attrs(
|
||||
cx: &mut DocContext<'_>,
|
||||
parent_module: Option<DefId>,
|
||||
old_attrs: Attrs<'_>,
|
||||
new_attrs: Option<Attrs<'_>>,
|
||||
old_attrs: &[ast::Attribute],
|
||||
new_attrs: Option<&[ast::Attribute]>,
|
||||
) -> (clean::Attributes, Option<Arc<clean::cfg::Cfg>>) {
|
||||
// NOTE: If we have additional attributes (from a re-export),
|
||||
// always insert them first. This ensure that re-export
|
||||
@ -331,7 +329,7 @@ pub(crate) fn build_impl(
|
||||
cx: &mut DocContext<'_>,
|
||||
parent_module: Option<DefId>,
|
||||
did: DefId,
|
||||
attrs: Option<Attrs<'_>>,
|
||||
attrs: Option<&[ast::Attribute]>,
|
||||
ret: &mut Vec<clean::Item>,
|
||||
) {
|
||||
if !cx.inlined.insert(did.into()) {
|
||||
|
@ -6,7 +6,7 @@
|
||||
let mut _0: (); // return place in scope 0 at $DIR/provenance_soundness.rs:+0:25: +0:25
|
||||
|
||||
bb0: {
|
||||
Retag([fn entry] _1); // scope 0 at $DIR/provenance_soundness.rs:+0:1: +0:27
|
||||
Retag([fn entry] _1); // scope 0 at $DIR/provenance_soundness.rs:+0:11: +0:13
|
||||
_0 = const (); // scope 0 at $DIR/provenance_soundness.rs:+0:25: +0:27
|
||||
return; // scope 0 at $DIR/provenance_soundness.rs:+0:27: +0:27
|
||||
}
|
||||
|
@ -52,8 +52,8 @@ fn bar() -> bool {
|
||||
Retag(_7); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14
|
||||
_6 = &(*_7); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14
|
||||
Retag(_6); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14
|
||||
Retag(_3); // scope 2 at $DIR/inline-retag.rs:16:1: 18:2
|
||||
Retag(_6); // scope 2 at $DIR/inline-retag.rs:16:1: 18:2
|
||||
Retag(_3); // scope 2 at $DIR/inline-retag.rs:16:8: 16:9
|
||||
Retag(_6); // scope 2 at $DIR/inline-retag.rs:16:17: 16:18
|
||||
StorageLive(_11); // scope 2 at $DIR/inline-retag.rs:17:5: 17:7
|
||||
_11 = (*_3); // scope 2 at $DIR/inline-retag.rs:17:5: 17:7
|
||||
StorageLive(_12); // scope 2 at $DIR/inline-retag.rs:17:11: 17:13
|
||||
|
@ -10,7 +10,7 @@ fn main::{closure#0}(_1: &[closure@main::{closure#0}], _2: &i32) -> &i32 {
|
||||
|
||||
bb0: {
|
||||
Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:+0:31: +0:48
|
||||
Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:+0:31: +0:48
|
||||
Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:+0:32: +0:33
|
||||
StorageLive(_3); // scope 0 at $DIR/retag.rs:42:13: 42:15
|
||||
_3 = _2; // scope 0 at $DIR/retag.rs:42:18: 42:19
|
||||
Retag(_3); // scope 0 at $DIR/retag.rs:42:18: 42:19
|
||||
|
@ -7,8 +7,8 @@ fn <impl at $DIR/retag.rs:12:1: 12:10>::foo(_1: &Test, _2: &mut i32) -> &mut i32
|
||||
let mut _3: &mut i32; // in scope 0 at $DIR/retag.rs:+1:9: +1:10
|
||||
|
||||
bb0: {
|
||||
Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:+0:5: +2:6
|
||||
Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:+0:5: +2:6
|
||||
Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:+0:16: +0:21
|
||||
Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:+0:23: +0:24
|
||||
StorageLive(_3); // scope 0 at $DIR/retag.rs:+1:9: +1:10
|
||||
_3 = &mut (*_2); // scope 0 at $DIR/retag.rs:+1:9: +1:10
|
||||
Retag(_3); // scope 0 at $DIR/retag.rs:+1:9: +1:10
|
||||
|
@ -6,8 +6,8 @@ fn <impl at $DIR/retag.rs:12:1: 12:10>::foo_shr(_1: &Test, _2: &i32) -> &i32 {
|
||||
let mut _0: &i32; // return place in scope 0 at $DIR/retag.rs:+0:42: +0:49
|
||||
|
||||
bb0: {
|
||||
Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:+0:5: +2:6
|
||||
Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:+0:5: +2:6
|
||||
Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:+0:20: +0:25
|
||||
Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:+0:27: +0:28
|
||||
_0 = _2; // scope 0 at $DIR/retag.rs:+1:9: +1:10
|
||||
Retag(_0); // scope 0 at $DIR/retag.rs:+1:9: +1:10
|
||||
return; // scope 0 at $DIR/retag.rs:+2:6: +2:6
|
||||
|
@ -549,7 +549,7 @@ struct ErrorWithMultiSpan {
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
#[warn_]
|
||||
#[warning]
|
||||
struct ErrorWithWarn {
|
||||
val: String,
|
||||
}
|
||||
@ -562,11 +562,11 @@ struct ErrorWithWarn {
|
||||
struct ErrorAttribute {}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[warning(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
//~^ ERROR `#[warning(...)]` is not a valid attribute
|
||||
#[warn_(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
//~^ ERROR `#[warn_(...)]` is not a valid attribute
|
||||
//~| ERROR diagnostic slug not specified
|
||||
//~| ERROR cannot find attribute `warning` in this scope
|
||||
struct WarningAttribute {}
|
||||
//~| ERROR cannot find attribute `warn_` in this scope
|
||||
struct WarnAttribute {}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[lint(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
|
@ -21,7 +21,7 @@ error: `#[nonsense(...)]` is not a valid attribute
|
||||
LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: only `diag`, `help`, `note` and `warn_` are valid attributes
|
||||
= help: only `diag`, `help`, `note` and `warning` are valid attributes
|
||||
|
||||
error: diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:53:1
|
||||
@ -329,7 +329,7 @@ error: `#[error(...)]` is not a valid attribute
|
||||
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: `error`, `warning` and `lint` have been replaced by `diag`
|
||||
= help: `error` and `lint` have been replaced by `diag`
|
||||
|
||||
error: diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:558:1
|
||||
@ -343,23 +343,23 @@ LL | | struct ErrorAttribute {}
|
||||
|
|
||||
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
|
||||
|
||||
error: `#[warning(...)]` is not a valid attribute
|
||||
error: `#[warn_(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:565:1
|
||||
|
|
||||
LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[warn_(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: `error`, `warning` and `lint` have been replaced by `diag`
|
||||
= help: `warn_` have been replaced by `warning`
|
||||
|
||||
error: diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:565:1
|
||||
|
|
||||
LL | / #[warning(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
LL | / #[warn_(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | struct WarningAttribute {}
|
||||
| |__________________________^
|
||||
LL | | struct WarnAttribute {}
|
||||
| |_______________________^
|
||||
|
|
||||
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(typeck::example_error)]`
|
||||
|
||||
@ -369,7 +369,7 @@ error: `#[lint(...)]` is not a valid attribute
|
||||
LL | #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: `error`, `warning` and `lint` have been replaced by `diag`
|
||||
= help: `error` and `lint` have been replaced by `diag`
|
||||
|
||||
error: diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:572:1
|
||||
@ -389,7 +389,7 @@ error: `#[lint(...)]` is not a valid attribute
|
||||
LL | #[lint(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: `error`, `warning` and `lint` have been replaced by `diag`
|
||||
= help: `error` and `lint` have been replaced by `diag`
|
||||
|
||||
error: diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:579:1
|
||||
@ -421,11 +421,11 @@ error: cannot find attribute `error` in this scope
|
||||
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
| ^^^^^
|
||||
|
||||
error: cannot find attribute `warning` in this scope
|
||||
error: cannot find attribute `warn_` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:565:3
|
||||
|
|
||||
LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
| ^^^^^^^
|
||||
LL | #[warn_(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
| ^^^^^ help: a built-in attribute with a similar name exists: `warn`
|
||||
|
||||
error: cannot find attribute `lint` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:572:3
|
||||
|
@ -510,12 +510,11 @@ enum AX {
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
#[warn_(parser::add_paren)]
|
||||
struct AY {
|
||||
}
|
||||
#[warning(parser::add_paren)]
|
||||
struct AY {}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
#[warn_(parser::add_paren)]
|
||||
#[warning(parser::add_paren)]
|
||||
struct AZ {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
@ -4,8 +4,8 @@ error[E0308]: mismatched types
|
||||
LL | Foo::<10, 12>
|
||||
| ^^^^^^^^^^^^^ expected `11`, found `12`
|
||||
|
|
||||
= note: expected type `11`
|
||||
found type `12`
|
||||
= note: expected constant `11`
|
||||
found constant `12`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -4,8 +4,8 @@ error[E0308]: mismatched types
|
||||
LL | Foo::<N, { N + 2 }>
|
||||
| ^^^^^^^^^^^^^^^^^^^ expected `{ N + 1 }`, found `{ N + 2 }`
|
||||
|
|
||||
= note: expected type `{ N + 1 }`
|
||||
found type `{ N + 2 }`
|
||||
= note: expected constant `{ N + 1 }`
|
||||
found constant `{ N + 2 }`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -22,8 +22,13 @@ error[E0308]: mismatched types
|
||||
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }`
|
||||
|
|
||||
= note: expected type `{ N as u128 }`
|
||||
found type `{ O as u128 }`
|
||||
= note: expected constant `{ N as u128 }`
|
||||
found constant `{ O as u128 }`
|
||||
note: required by a bound in `use_trait_impl::assert_impl`
|
||||
--> $DIR/abstract-const-as-cast-3.rs:14:23
|
||||
|
|
||||
LL | fn assert_impl<T: Trait>() {}
|
||||
| ^^^^^ required by this bound in `use_trait_impl::assert_impl`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/abstract-const-as-cast-3.rs:20:19
|
||||
@ -49,8 +54,13 @@ error[E0308]: mismatched types
|
||||
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }`
|
||||
|
|
||||
= note: expected type `{ N as _ }`
|
||||
found type `{ O as u128 }`
|
||||
= note: expected constant `{ N as _ }`
|
||||
found constant `{ O as u128 }`
|
||||
note: required by a bound in `use_trait_impl::assert_impl`
|
||||
--> $DIR/abstract-const-as-cast-3.rs:14:23
|
||||
|
|
||||
LL | fn assert_impl<T: Trait>() {}
|
||||
| ^^^^^ required by this bound in `use_trait_impl::assert_impl`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/abstract-const-as-cast-3.rs:23:5
|
||||
@ -58,8 +68,13 @@ error[E0308]: mismatched types
|
||||
LL | assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12`, found `13`
|
||||
|
|
||||
= note: expected type `12`
|
||||
found type `13`
|
||||
= note: expected constant `12`
|
||||
found constant `13`
|
||||
note: required by a bound in `use_trait_impl::assert_impl`
|
||||
--> $DIR/abstract-const-as-cast-3.rs:14:23
|
||||
|
|
||||
LL | fn assert_impl<T: Trait>() {}
|
||||
| ^^^^^ required by this bound in `use_trait_impl::assert_impl`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/abstract-const-as-cast-3.rs:25:5
|
||||
@ -67,8 +82,13 @@ error[E0308]: mismatched types
|
||||
LL | assert_impl::<HasCastInTraitImpl<14, 13>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13`, found `14`
|
||||
|
|
||||
= note: expected type `13`
|
||||
found type `14`
|
||||
= note: expected constant `13`
|
||||
found constant `14`
|
||||
note: required by a bound in `use_trait_impl::assert_impl`
|
||||
--> $DIR/abstract-const-as-cast-3.rs:14:23
|
||||
|
|
||||
LL | fn assert_impl<T: Trait>() {}
|
||||
| ^^^^^ required by this bound in `use_trait_impl::assert_impl`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/abstract-const-as-cast-3.rs:35:19
|
||||
@ -94,8 +114,13 @@ error[E0308]: mismatched types
|
||||
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }`
|
||||
|
|
||||
= note: expected type `{ N as u128 }`
|
||||
found type `{ O as u128 }`
|
||||
= note: expected constant `{ N as u128 }`
|
||||
found constant `{ O as u128 }`
|
||||
note: required by a bound in `use_trait_impl_2::assert_impl`
|
||||
--> $DIR/abstract-const-as-cast-3.rs:32:23
|
||||
|
|
||||
LL | fn assert_impl<T: Trait>() {}
|
||||
| ^^^^^ required by this bound in `use_trait_impl_2::assert_impl`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/abstract-const-as-cast-3.rs:38:19
|
||||
@ -121,8 +146,13 @@ error[E0308]: mismatched types
|
||||
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }`
|
||||
|
|
||||
= note: expected type `{ N as _ }`
|
||||
found type `{ O as u128 }`
|
||||
= note: expected constant `{ N as _ }`
|
||||
found constant `{ O as u128 }`
|
||||
note: required by a bound in `use_trait_impl_2::assert_impl`
|
||||
--> $DIR/abstract-const-as-cast-3.rs:32:23
|
||||
|
|
||||
LL | fn assert_impl<T: Trait>() {}
|
||||
| ^^^^^ required by this bound in `use_trait_impl_2::assert_impl`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/abstract-const-as-cast-3.rs:41:5
|
||||
@ -130,8 +160,13 @@ error[E0308]: mismatched types
|
||||
LL | assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12`, found `13`
|
||||
|
|
||||
= note: expected type `12`
|
||||
found type `13`
|
||||
= note: expected constant `12`
|
||||
found constant `13`
|
||||
note: required by a bound in `use_trait_impl_2::assert_impl`
|
||||
--> $DIR/abstract-const-as-cast-3.rs:32:23
|
||||
|
|
||||
LL | fn assert_impl<T: Trait>() {}
|
||||
| ^^^^^ required by this bound in `use_trait_impl_2::assert_impl`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/abstract-const-as-cast-3.rs:43:5
|
||||
@ -139,8 +174,13 @@ error[E0308]: mismatched types
|
||||
LL | assert_impl::<HasCastInTraitImpl<14, 13>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13`, found `14`
|
||||
|
|
||||
= note: expected type `13`
|
||||
found type `14`
|
||||
= note: expected constant `13`
|
||||
found constant `14`
|
||||
note: required by a bound in `use_trait_impl_2::assert_impl`
|
||||
--> $DIR/abstract-const-as-cast-3.rs:32:23
|
||||
|
|
||||
LL | fn assert_impl<T: Trait>() {}
|
||||
| ^^^^^ required by this bound in `use_trait_impl_2::assert_impl`
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
@ -4,8 +4,8 @@ error[E0308]: mismatched types
|
||||
LL | [0; size_of::<Foo<T>>()]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::<T>()`, found `size_of::<Foo<T>>()`
|
||||
|
|
||||
= note: expected type `size_of::<T>()`
|
||||
found type `size_of::<Foo<T>>()`
|
||||
= note: expected constant `size_of::<T>()`
|
||||
found constant `size_of::<Foo<T>>()`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/different-fn.rs:10:9
|
||||
|
@ -4,8 +4,8 @@ error[E0308]: mismatched types
|
||||
LL | ArrayHolder([0; Self::SIZE])
|
||||
| ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
|
||||
|
|
||||
= note: expected type `X`
|
||||
found type `Self::SIZE`
|
||||
= note: expected constant `X`
|
||||
found constant `Self::SIZE`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/issue-62504.rs:18:25
|
||||
|
@ -4,8 +4,15 @@ error[E0308]: mismatched types
|
||||
LL | let x: Arr<{usize::MAX}> = Arr {};
|
||||
| ^^^^^^^^^^^^^^^^^ expected `false`, found `true`
|
||||
|
|
||||
= note: expected type `false`
|
||||
found type `true`
|
||||
= note: expected constant `false`
|
||||
found constant `true`
|
||||
note: required by a bound in `Arr`
|
||||
--> $DIR/issue-72819-generic-in-const-eval.rs:8:39
|
||||
|
|
||||
LL | struct Arr<const N: usize>
|
||||
| --- required by a bound in this
|
||||
LL | where Assert::<{N < usize::MAX / 2}>: IsTrue,
|
||||
| ^^^^^^ required by this bound in `Arr`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-72819-generic-in-const-eval.rs:20:32
|
||||
@ -13,8 +20,15 @@ error[E0308]: mismatched types
|
||||
LL | let x: Arr<{usize::MAX}> = Arr {};
|
||||
| ^^^ expected `false`, found `true`
|
||||
|
|
||||
= note: expected type `false`
|
||||
found type `true`
|
||||
= note: expected constant `false`
|
||||
found constant `true`
|
||||
note: required by a bound in `Arr`
|
||||
--> $DIR/issue-72819-generic-in-const-eval.rs:8:39
|
||||
|
|
||||
LL | struct Arr<const N: usize>
|
||||
| --- required by a bound in this
|
||||
LL | where Assert::<{N < usize::MAX / 2}>: IsTrue,
|
||||
| ^^^^^^ required by this bound in `Arr`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user