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:
bors 2022-08-29 05:12:53 +00:00
commit 94b2b15e63
115 changed files with 1289 additions and 524 deletions

View File

@ -3631,6 +3631,7 @@ dependencies = [
"rustc_macros",
"rustc_middle",
"rustc_serialize",
"rustc_session",
"rustc_span",
"rustc_target",
"smallvec",

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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(_), _)),

View File

@ -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)

View File

@ -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;

View File

@ -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));
}

View File

@ -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() {

View File

@ -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 {

View File

@ -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);

View File

@ -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 => {

View File

@ -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);

View File

@ -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,

View File

@ -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,
}
);

View File

@ -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 {:?} ({:?})",

View File

@ -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();

View File

@ -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).

View File

@ -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);

View File

@ -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
{

View File

@ -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")
}
}

View 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

View File

@ -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",

View File

@ -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"] }

View 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);
}
};
}
}

View File

@ -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)]

View File

@ -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()),
}
}
}

View File

@ -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);

View File

@ -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(

View File

@ -34,5 +34,6 @@ extern crate tracing;
#[macro_use]
extern crate rustc_middle;
mod errors;
pub mod infer;
pub mod traits;

View File

@ -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!(),
}
}

View File

@ -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))

View File

@ -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,

View File

@ -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();

View File

@ -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]
}
}

View File

@ -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],
};

View File

@ -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)?;
}
}

View File

@ -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() {

View File

@ -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.

View File

@ -951,7 +951,7 @@ macro_rules! basic_blocks {
$body.basic_blocks.as_mut_preserves_cfg()
};
($body:ident,) => {
$body.basic_blocks()
$body.basic_blocks
};
}

View File

@ -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.

View File

@ -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: {:?}",

View File

@ -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) {

View File

@ -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<_>>()

View File

@ -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| {

View File

@ -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);

View File

@ -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(),

View File

@ -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))
});

View File

@ -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 {

View File

@ -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;
}

View File

@ -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 {

View File

@ -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();

View File

@ -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)),
}),

View File

@ -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.

View File

@ -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(),

View File

@ -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);
}
}

View File

@ -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))
}
}

View File

@ -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;

View File

@ -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 {

View File

@ -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);

View File

@ -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.

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -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;
}

View File

@ -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 { .. }

View File

@ -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,

View File

@ -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);

View File

@ -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() {

View File

@ -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)

View File

@ -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) {

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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;

View File

@ -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<()>,
}

View File

@ -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();
}
}
}

View File

@ -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,

View File

@ -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())
}
}

View File

@ -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

View File

@ -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

View File

@ -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))) }

View File

@ -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()) {

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")]

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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