mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 22:34:05 +00:00
Auto merge of #129936 - matthiaskrgr:rollup-0s8xycb, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #127692 (Suggest `impl Trait` for References to Bare Trait in Function Header) - #128701 (Don't Suggest Labeling `const` and `unsafe` Blocks ) - #128934 (Non-exhaustive structs may be empty) - #129630 (Document the broken C ABI of `wasm32-unknown-unknown`) - #129863 (update comment regarding TargetOptions.features) - #129896 (do not attempt to prove unknowable goals) - #129926 (Move `SanityCheck` and `MirPass`) - #129928 (rustc_driver_impl: remove some old dead logic) - #129930 (include 1.80.1 release notes on master) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
009e73825a
@ -112,6 +112,14 @@ tools.
|
||||
|
||||
- [Add a Rust-for Linux `auto` CI job to check kernel builds.](https://github.com/rust-lang/rust/pull/125209/)
|
||||
|
||||
Version 1.80.1 (2024-08-08)
|
||||
===========================
|
||||
|
||||
<a id="1.80.1"></a>
|
||||
|
||||
- [Fix miscompilation in the jump threading MIR optimization when comparing floats](https://github.com/rust-lang/rust/pull/128271)
|
||||
- [Revert changes to the `dead_code` lint from 1.80.0](https://github.com/rust-lang/rust/pull/128618)
|
||||
|
||||
Version 1.80.0 (2024-07-25)
|
||||
==========================
|
||||
|
||||
|
@ -61,7 +61,6 @@ use rustc_session::lint::{Lint, LintId};
|
||||
use rustc_session::output::collect_crate_types;
|
||||
use rustc_session::{config, filesearch, EarlyDiagCtxt, Session};
|
||||
use rustc_span::source_map::FileLoader;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::FileName;
|
||||
use rustc_target::json::ToJson;
|
||||
use rustc_target::spec::{Target, TargetTriple};
|
||||
@ -777,16 +776,8 @@ fn print_crate_info(
|
||||
.config
|
||||
.iter()
|
||||
.filter_map(|&(name, value)| {
|
||||
// Note that crt-static is a specially recognized cfg
|
||||
// directive that's printed out here as part of
|
||||
// rust-lang/rust#37406, but in general the
|
||||
// `target_feature` cfg is gated under
|
||||
// rust-lang/rust#29717. For now this is just
|
||||
// specifically allowing the crt-static cfg and that's
|
||||
// it, this is intended to get into Cargo and then go
|
||||
// through to build scripts.
|
||||
if (name != sym::target_feature || value != Some(sym::crt_dash_static))
|
||||
&& !sess.is_nightly_build()
|
||||
// On stable, exclude unstable flags.
|
||||
if !sess.is_nightly_build()
|
||||
&& find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
|
||||
{
|
||||
return None;
|
||||
|
@ -133,9 +133,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
return;
|
||||
};
|
||||
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name);
|
||||
if sugg.is_empty() {
|
||||
return;
|
||||
};
|
||||
diag.multipart_suggestion(
|
||||
format!(
|
||||
"alternatively use a blanket implementation to implement `{of_trait_name}` for \
|
||||
@ -170,6 +167,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
|
||||
// FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
|
||||
// and suggest `Trait0<Ty = impl Trait1>`.
|
||||
// Functions are found in three different contexts.
|
||||
// 1. Independent functions
|
||||
// 2. Functions inside trait blocks
|
||||
// 3. Functions inside impl blocks
|
||||
let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
|
||||
(sig, generics, None)
|
||||
@ -180,6 +181,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
owner_id,
|
||||
..
|
||||
}) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
|
||||
hir::Node::ImplItem(hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Fn(sig, _),
|
||||
generics,
|
||||
owner_id,
|
||||
..
|
||||
}) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
|
||||
_ => return false,
|
||||
};
|
||||
let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
|
||||
@ -187,6 +194,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
};
|
||||
let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
|
||||
let mut is_downgradable = true;
|
||||
|
||||
// Check if trait object is safe for suggesting dynamic dispatch.
|
||||
let is_object_safe = match self_ty.kind {
|
||||
hir::TyKind::TraitObject(objects, ..) => {
|
||||
objects.iter().all(|(o, _)| match o.trait_ref.path.res {
|
||||
@ -202,8 +211,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let borrowed = matches!(
|
||||
tcx.parent_hir_node(self_ty.hir_id),
|
||||
hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. })
|
||||
);
|
||||
|
||||
// Suggestions for function return type.
|
||||
if let hir::FnRetTy::Return(ty) = sig.decl.output
|
||||
&& ty.hir_id == self_ty.hir_id
|
||||
&& ty.peel_refs().hir_id == self_ty.hir_id
|
||||
{
|
||||
let pre = if !is_object_safe {
|
||||
format!("`{trait_name}` is not object safe, ")
|
||||
@ -214,14 +230,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
"{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
|
||||
single underlying type",
|
||||
);
|
||||
|
||||
diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);
|
||||
|
||||
// Suggest `Box<dyn Trait>` for return type
|
||||
if is_object_safe {
|
||||
diag.multipart_suggestion_verbose(
|
||||
"alternatively, you can return an owned trait object",
|
||||
// If the return type is `&Trait`, we don't want
|
||||
// the ampersand to be displayed in the `Box<dyn Trait>`
|
||||
// suggestion.
|
||||
let suggestion = if borrowed {
|
||||
vec![(ty.span, format!("Box<dyn {trait_name}>"))]
|
||||
} else {
|
||||
vec![
|
||||
(ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
|
||||
(ty.span.shrink_to_hi(), ">".to_string()),
|
||||
],
|
||||
]
|
||||
};
|
||||
|
||||
diag.multipart_suggestion_verbose(
|
||||
"alternatively, you can return an owned trait object",
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if is_downgradable {
|
||||
@ -230,24 +258,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Suggestions for function parameters.
|
||||
for ty in sig.decl.inputs {
|
||||
if ty.hir_id != self_ty.hir_id {
|
||||
if ty.peel_refs().hir_id != self_ty.hir_id {
|
||||
continue;
|
||||
}
|
||||
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name);
|
||||
if !sugg.is_empty() {
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!("use a new generic type parameter, constrained by `{trait_name}`"),
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.multipart_suggestion_verbose(
|
||||
"you can also use an opaque type, but users won't be able to specify the type \
|
||||
parameter when calling the `fn`, having to rely exclusively on type inference",
|
||||
impl_sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!("use a new generic type parameter, constrained by `{trait_name}`"),
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.multipart_suggestion_verbose(
|
||||
"you can also use an opaque type, but users won't be able to specify the type \
|
||||
parameter when calling the `fn`, having to rely exclusively on type inference",
|
||||
impl_sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
if !is_object_safe {
|
||||
diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
|
||||
if is_downgradable {
|
||||
@ -255,14 +283,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
diag.downgrade_to_delayed_bug();
|
||||
}
|
||||
} else {
|
||||
// No ampersand in suggestion if it's borrowed already
|
||||
let (dyn_str, paren_dyn_str) =
|
||||
if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
|
||||
|
||||
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
|
||||
// There are more than one trait bound, we need surrounding parentheses.
|
||||
vec![
|
||||
(self_ty.span.shrink_to_lo(), "&(dyn ".to_string()),
|
||||
(self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()),
|
||||
(self_ty.span.shrink_to_hi(), ")".to_string()),
|
||||
]
|
||||
} else {
|
||||
vec![(self_ty.span.shrink_to_lo(), "&dyn ".to_string())]
|
||||
vec![(self_ty.span.shrink_to_lo(), dyn_str.to_string())]
|
||||
};
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!(
|
||||
|
@ -3,8 +3,6 @@
|
||||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::{iter, mem};
|
||||
@ -26,7 +24,6 @@ use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
@ -106,65 +103,6 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static PASS_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
|
||||
RefCell::new(FxHashMap::default())
|
||||
};
|
||||
}
|
||||
|
||||
/// Converts a MIR pass name into a snake case form to match the profiling naming style.
|
||||
fn to_profiler_name(type_name: &'static str) -> &'static str {
|
||||
PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
|
||||
Entry::Occupied(e) => *e.get(),
|
||||
Entry::Vacant(e) => {
|
||||
let snake_case: String = type_name
|
||||
.chars()
|
||||
.flat_map(|c| {
|
||||
if c.is_ascii_uppercase() {
|
||||
vec!['_', c.to_ascii_lowercase()]
|
||||
} else if c == '-' {
|
||||
vec!['_']
|
||||
} else {
|
||||
vec![c]
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let result = &*String::leak(format!("mir_pass{}", snake_case));
|
||||
e.insert(result);
|
||||
result
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// A streamlined trait that you can implement to create a pass; the
|
||||
/// pass will be named after the type, and it will consist of a main
|
||||
/// loop that goes over each available MIR and applies `run_pass`.
|
||||
pub trait MirPass<'tcx> {
|
||||
fn name(&self) -> &'static str {
|
||||
// FIXME Simplify the implementation once more `str` methods get const-stable.
|
||||
// See copypaste in `MirLint`
|
||||
const {
|
||||
let name = std::any::type_name::<Self>();
|
||||
crate::util::common::c_name(name)
|
||||
}
|
||||
}
|
||||
|
||||
fn profiler_name(&self) -> &'static str {
|
||||
to_profiler_name(self.name())
|
||||
}
|
||||
|
||||
/// Returns `true` if this pass is enabled with the current combination of compiler flags.
|
||||
fn is_enabled(&self, _sess: &Session) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
|
||||
|
||||
fn is_mir_dump_enabled(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl MirPhase {
|
||||
/// Gets the index of the current MirPhase within the set of all `MirPhase`s.
|
||||
///
|
||||
|
@ -81,10 +81,6 @@ impl<'tcx> VariantDef {
|
||||
adt: ty::AdtDef<'_>,
|
||||
) -> InhabitedPredicate<'tcx> {
|
||||
debug_assert!(!adt.is_union());
|
||||
if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
|
||||
// Non-exhaustive variants from other crates are always considered inhabited.
|
||||
return InhabitedPredicate::True;
|
||||
}
|
||||
InhabitedPredicate::all(
|
||||
tcx,
|
||||
self.fields.iter().map(|field| {
|
||||
|
@ -20,19 +20,3 @@ pub fn to_readable_str(mut val: usize) -> String {
|
||||
|
||||
groups.join("_")
|
||||
}
|
||||
|
||||
// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }`
|
||||
pub const fn c_name(name: &'static str) -> &'static str {
|
||||
// FIXME Simplify the implementation once more `str` methods get const-stable.
|
||||
// and inline into call site
|
||||
let bytes = name.as_bytes();
|
||||
let mut i = bytes.len();
|
||||
while i > 0 && bytes[i - 1] != b':' {
|
||||
i = i - 1;
|
||||
}
|
||||
let (_, bytes) = bytes.split_at(i);
|
||||
match std::str::from_utf8(bytes) {
|
||||
Ok(name) => name,
|
||||
Err(_) => name,
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc_ast::MetaItem;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::mir::{self, Body, Local, Location, MirPass};
|
||||
use rustc_middle::mir::{self, Body, Local, Location};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
@ -18,8 +18,6 @@ use crate::impls::{
|
||||
use crate::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
|
||||
use crate::{Analysis, JoinSemiLattice, ResultsCursor};
|
||||
|
||||
pub struct SanityCheck;
|
||||
|
||||
fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option<MetaItem> {
|
||||
for attr in tcx.get_attrs(def_id, sym::rustc_mir) {
|
||||
let items = attr.meta_item_list();
|
||||
@ -33,53 +31,50 @@ fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option<Me
|
||||
None
|
||||
}
|
||||
|
||||
// FIXME: This should be a `MirLint`, but it needs to be moved back to `rustc_mir_transform` first.
|
||||
impl<'tcx> MirPass<'tcx> for SanityCheck {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let def_id = body.source.def_id();
|
||||
if !tcx.has_attr(def_id, sym::rustc_mir) {
|
||||
debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
|
||||
return;
|
||||
} else {
|
||||
debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
|
||||
}
|
||||
pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
let def_id = body.source.def_id();
|
||||
if !tcx.has_attr(def_id, sym::rustc_mir) {
|
||||
debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
|
||||
return;
|
||||
} else {
|
||||
debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
|
||||
}
|
||||
|
||||
let param_env = tcx.param_env(def_id);
|
||||
let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
|
||||
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
|
||||
let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint();
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
|
||||
let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint();
|
||||
|
||||
sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
|
||||
}
|
||||
sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
|
||||
}
|
||||
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
|
||||
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint();
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
|
||||
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint();
|
||||
|
||||
sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
|
||||
}
|
||||
sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
|
||||
}
|
||||
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
|
||||
let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint();
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
|
||||
let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint();
|
||||
|
||||
sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
|
||||
}
|
||||
sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
|
||||
}
|
||||
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
|
||||
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
|
||||
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
|
||||
|
||||
sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
|
||||
}
|
||||
sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
|
||||
}
|
||||
|
||||
if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
|
||||
tcx.dcx().emit_fatal(StopAfterDataFlowEndedCompilation);
|
||||
}
|
||||
if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
|
||||
tcx.dcx().emit_fatal(StopAfterDataFlowEndedCompilation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ use rustc_target::spec::PanicStrategy;
|
||||
#[derive(PartialEq)]
|
||||
pub struct AbortUnwindingCalls;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
|
||||
impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let def_id = body.source.def_id();
|
||||
let kind = tcx.def_kind(def_id);
|
||||
|
@ -30,7 +30,7 @@ pub use self::AddCallGuards::*;
|
||||
*
|
||||
*/
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for AddCallGuards {
|
||||
impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
|
||||
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
self.add_call_guards(body);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ use crate::util;
|
||||
/// blowup.
|
||||
pub struct AddMovesForPackedDrops;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops {
|
||||
impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span);
|
||||
add_moves_for_packed_drops(tcx, body);
|
||||
|
@ -48,7 +48,7 @@ fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> b
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for AddRetag {
|
||||
impl<'tcx> crate::MirPass<'tcx> for AddRetag {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.opts.unstable_opts.mir_emit_retag
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
checker.patcher.apply(body);
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for Subtyper {
|
||||
impl<'tcx> crate::MirPass<'tcx> for Subtyper {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
subtype_finder(tcx, body);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use tracing::{debug, trace};
|
||||
|
||||
pub struct CheckAlignment;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for CheckAlignment {
|
||||
impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
|
||||
fn is_enabled(&self, sess: &Session) -> bool {
|
||||
// FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows
|
||||
if sess.target.llvm_target == "i686-pc-windows-msvc" {
|
||||
|
@ -6,11 +6,11 @@ use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::{errors, MirLint};
|
||||
use crate::errors;
|
||||
|
||||
pub struct CheckConstItemMutation;
|
||||
|
||||
impl<'tcx> MirLint<'tcx> for CheckConstItemMutation {
|
||||
impl<'tcx> crate::MirLint<'tcx> for CheckConstItemMutation {
|
||||
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
let mut checker = ConstMutationChecker { body, tcx, target_local: None };
|
||||
checker.visit_body(body);
|
||||
|
@ -3,11 +3,11 @@ use rustc_middle::mir::*;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
|
||||
use crate::{errors, util, MirLint};
|
||||
use crate::{errors, util};
|
||||
|
||||
pub struct CheckPackedRef;
|
||||
|
||||
impl<'tcx> MirLint<'tcx> for CheckPackedRef {
|
||||
impl<'tcx> crate::MirLint<'tcx> for CheckPackedRef {
|
||||
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
let param_env = tcx.param_env(body.source.def_id());
|
||||
let source_info = SourceInfo::outermost(body.span);
|
||||
|
@ -21,11 +21,9 @@ use rustc_middle::mir::{Body, BorrowKind, CastKind, Rvalue, StatementKind, Termi
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
use crate::MirPass;
|
||||
|
||||
pub struct CleanupPostBorrowck;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
|
||||
impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck {
|
||||
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
for basic_block in body.basic_blocks.as_mut() {
|
||||
for statement in basic_block.statements.iter_mut() {
|
||||
|
@ -19,7 +19,7 @@ use crate::ssa::SsaLocals;
|
||||
/// We want to replace all those locals by `_a`, either copied or moved.
|
||||
pub struct CopyProp;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for CopyProp {
|
||||
impl<'tcx> crate::MirPass<'tcx> for CopyProp {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 1
|
||||
}
|
||||
|
@ -1535,7 +1535,7 @@ fn check_field_tys_sized<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for StateTransform {
|
||||
impl<'tcx> crate::MirPass<'tcx> for StateTransform {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let Some(old_yield_ty) = body.yield_ty() else {
|
||||
// This only applies to coroutines
|
||||
|
@ -28,14 +28,13 @@ use tracing::{debug, debug_span, instrument, trace};
|
||||
use crate::coverage::counters::{CounterIncrementSite, CoverageCounters};
|
||||
use crate::coverage::graph::CoverageGraph;
|
||||
use crate::coverage::mappings::ExtractedMappings;
|
||||
use crate::MirPass;
|
||||
|
||||
/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
|
||||
/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
|
||||
/// to construct the coverage map.
|
||||
pub struct InstrumentCoverage;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
|
||||
impl<'tcx> crate::MirPass<'tcx> for InstrumentCoverage {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.instrument_coverage()
|
||||
}
|
||||
|
@ -8,11 +8,9 @@ use rustc_middle::mir::{
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::MirPass;
|
||||
|
||||
pub struct CtfeLimit;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for CtfeLimit {
|
||||
impl<'tcx> crate::MirPass<'tcx> for CtfeLimit {
|
||||
#[instrument(skip(self, _tcx, body))]
|
||||
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let doms = body.basic_blocks.dominators();
|
||||
|
@ -28,7 +28,7 @@ const PLACE_LIMIT: usize = 100;
|
||||
|
||||
pub struct DataflowConstProp;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for DataflowConstProp {
|
||||
impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 3
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ pub enum DeadStoreElimination {
|
||||
Final,
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
|
||||
impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination {
|
||||
fn name(&self) -> &'static str {
|
||||
match self {
|
||||
DeadStoreElimination::Initial => "DeadStoreElimination-initial",
|
||||
|
@ -15,7 +15,7 @@ use super::simplify::simplify_cfg;
|
||||
|
||||
pub struct DeduplicateBlocks;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
|
||||
impl<'tcx> crate::MirPass<'tcx> for DeduplicateBlocks {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 4
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
checker.patcher.apply(body);
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for Derefer {
|
||||
impl<'tcx> crate::MirPass<'tcx> for Derefer {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
deref_finder(tcx, body);
|
||||
}
|
||||
|
@ -146,11 +146,9 @@ use rustc_mir_dataflow::points::{save_as_intervals, DenseLocationMap, PointIndex
|
||||
use rustc_mir_dataflow::Analysis;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use crate::MirPass;
|
||||
|
||||
pub struct DestinationPropagation;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for DestinationPropagation {
|
||||
impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
// For now, only run at MIR opt level 3. Two things need to be changed before this can be
|
||||
// turned on by default:
|
||||
|
@ -7,11 +7,9 @@ use rustc_middle::mir::{write_mir_pretty, Body};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{OutFileName, OutputType};
|
||||
|
||||
use crate::MirPass;
|
||||
|
||||
pub struct Marker(pub &'static str);
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for Marker {
|
||||
impl<'tcx> crate::MirPass<'tcx> for Marker {
|
||||
fn name(&self) -> &'static str {
|
||||
self.0
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ use super::simplify::simplify_cfg;
|
||||
/// ```
|
||||
pub struct EarlyOtherwiseBranch;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
|
||||
impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 2
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> {
|
||||
|
||||
pub struct ElaborateBoxDerefs;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
|
||||
impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
if let Some(def_id) = tcx.lang_items().owned_box() {
|
||||
let unique_did = tcx.adt_def(def_id).non_enum_variant().fields[FieldIdx::ZERO].did;
|
||||
|
@ -49,7 +49,7 @@ use crate::deref_separator::deref_finder;
|
||||
/// ```
|
||||
pub struct ElaborateDrops;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for ElaborateDrops {
|
||||
impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops {
|
||||
#[instrument(level = "trace", skip(self, tcx, body))]
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
|
||||
|
@ -9,11 +9,11 @@ use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::{errors, MirLint};
|
||||
use crate::errors;
|
||||
|
||||
pub struct FunctionItemReferences;
|
||||
|
||||
impl<'tcx> MirLint<'tcx> for FunctionItemReferences {
|
||||
impl<'tcx> crate::MirLint<'tcx> for FunctionItemReferences {
|
||||
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
let mut checker = FunctionItemRefChecker { tcx, body };
|
||||
checker.visit_body(body);
|
||||
|
@ -111,7 +111,7 @@ use crate::ssa::{AssignedValue, SsaLocals};
|
||||
|
||||
pub struct GVN;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for GVN {
|
||||
impl<'tcx> crate::MirPass<'tcx> for GVN {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 2
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ struct CallSite<'tcx> {
|
||||
source_info: SourceInfo,
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for Inline {
|
||||
impl<'tcx> crate::MirPass<'tcx> for Inline {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
// FIXME(#127234): Coverage instrumentation currently doesn't handle inlined
|
||||
// MIR correctly when Modified Condition/Decision Coverage is enabled.
|
||||
|
@ -27,7 +27,7 @@ impl InstSimplify {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for InstSimplify {
|
||||
impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
|
||||
fn name(&self) -> &'static str {
|
||||
self.name()
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ const MAX_BACKTRACK: usize = 5;
|
||||
const MAX_COST: usize = 100;
|
||||
const MAX_PLACES: usize = 100;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for JumpThreading {
|
||||
impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 2
|
||||
}
|
||||
|
@ -25,11 +25,10 @@ use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, Va
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::errors::{AssertLint, AssertLintKind};
|
||||
use crate::MirLint;
|
||||
|
||||
pub struct KnownPanicsLint;
|
||||
|
||||
impl<'tcx> MirLint<'tcx> for KnownPanicsLint {
|
||||
impl<'tcx> crate::MirLint<'tcx> for KnownPanicsLint {
|
||||
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
if body.tainted_by_errors.is_some() {
|
||||
return;
|
||||
|
@ -27,7 +27,7 @@ pub struct EnumSizeOpt {
|
||||
pub(crate) discrepancy: u64,
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for EnumSizeOpt {
|
||||
impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
|
||||
fn is_enabled(&self, sess: &Session) -> bool {
|
||||
// There are some differences in behavior on wasm and ARM that are not properly
|
||||
// understood, so we conservatively treat this optimization as unsound:
|
||||
|
@ -26,13 +26,12 @@ use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::{
|
||||
AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl,
|
||||
MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
|
||||
MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
|
||||
Statement, StatementKind, TerminatorKind, START_BLOCK,
|
||||
};
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_middle::{bug, query, span_bug};
|
||||
use rustc_mir_dataflow::rustc_peek;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{sym, DUMMY_SP};
|
||||
use rustc_trait_selection::traits;
|
||||
@ -41,7 +40,7 @@ use tracing::{debug, trace};
|
||||
#[macro_use]
|
||||
mod pass_manager;
|
||||
|
||||
use pass_manager::{self as pm, Lint, MirLint, WithMinOptLevel};
|
||||
use pass_manager::{self as pm, Lint, MirLint, MirPass, WithMinOptLevel};
|
||||
|
||||
mod abort_unwinding_calls;
|
||||
mod add_call_guards;
|
||||
@ -96,6 +95,7 @@ mod remove_unneeded_drops;
|
||||
mod remove_zsts;
|
||||
mod required_consts;
|
||||
mod reveal_all;
|
||||
mod sanity_check;
|
||||
mod shim;
|
||||
mod ssa;
|
||||
// This pass is public to allow external drivers to perform MIR cleanup
|
||||
@ -288,7 +288,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
|
||||
&Lint(function_item_references::FunctionItemReferences),
|
||||
// What we need to do constant evaluation.
|
||||
&simplify::SimplifyCfg::Initial,
|
||||
&rustc_peek::SanityCheck, // Just a lint
|
||||
&Lint(sanity_check::SanityCheck),
|
||||
],
|
||||
None,
|
||||
);
|
||||
|
@ -9,7 +9,7 @@ use crate::take_array;
|
||||
|
||||
pub struct LowerIntrinsics;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
|
||||
impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let local_decls = &body.local_decls;
|
||||
for block in body.basic_blocks.as_mut() {
|
||||
|
@ -7,7 +7,7 @@ use rustc_middle::ty::TyCtxt;
|
||||
|
||||
pub struct LowerSliceLenCalls;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls {
|
||||
impl<'tcx> crate::MirPass<'tcx> for LowerSliceLenCalls {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() > 0
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use super::simplify::simplify_cfg;
|
||||
|
||||
pub struct MatchBranchSimplification;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
||||
impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 1
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{self, Location, MentionedItem, MirPass};
|
||||
use rustc_middle::mir::{self, Location, MentionedItem};
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::Session;
|
||||
@ -13,7 +13,7 @@ struct MentionedItemsVisitor<'a, 'tcx> {
|
||||
mentioned_items: &'a mut Vec<Spanned<MentionedItem<'tcx>>>,
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for MentionedItems {
|
||||
impl<'tcx> crate::MirPass<'tcx> for MentionedItems {
|
||||
fn is_enabled(&self, _sess: &Session) -> bool {
|
||||
// If this pass is skipped the collector assume that nothing got mentioned! We could
|
||||
// potentially skip it in opt-level 0 if we are sure that opt-level will never *remove* uses
|
||||
|
@ -9,7 +9,7 @@ use crate::simplify;
|
||||
|
||||
pub struct MultipleReturnTerminators;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
|
||||
impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 4
|
||||
}
|
||||
|
@ -8,8 +8,6 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use crate::MirPass;
|
||||
|
||||
/// This pass looks for MIR that always copies the same local into the return place and eliminates
|
||||
/// the copy by renaming all uses of that local to `_0`.
|
||||
///
|
||||
@ -34,7 +32,7 @@ use crate::MirPass;
|
||||
/// [#71003]: https://github.com/rust-lang/rust/pull/71003
|
||||
pub struct RenameReturnPlace;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
|
||||
impl<'tcx> crate::MirPass<'tcx> for RenameReturnPlace {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
// unsound: #111005
|
||||
sess.mir_opt_level() > 0 && sess.opts.unstable_opts.unsound_mir_opts
|
||||
|
@ -1,19 +1,99 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use tracing::trace;
|
||||
|
||||
use crate::lint::lint_body;
|
||||
use crate::{validate, MirPass};
|
||||
use crate::validate;
|
||||
|
||||
/// Just like `MirPass`, except it cannot mutate `Body`.
|
||||
pub trait MirLint<'tcx> {
|
||||
thread_local! {
|
||||
static PASS_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
|
||||
RefCell::new(FxHashMap::default())
|
||||
};
|
||||
}
|
||||
|
||||
/// Converts a MIR pass name into a snake case form to match the profiling naming style.
|
||||
fn to_profiler_name(type_name: &'static str) -> &'static str {
|
||||
PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
|
||||
Entry::Occupied(e) => *e.get(),
|
||||
Entry::Vacant(e) => {
|
||||
let snake_case: String = type_name
|
||||
.chars()
|
||||
.flat_map(|c| {
|
||||
if c.is_ascii_uppercase() {
|
||||
vec!['_', c.to_ascii_lowercase()]
|
||||
} else if c == '-' {
|
||||
vec!['_']
|
||||
} else {
|
||||
vec![c]
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let result = &*String::leak(format!("mir_pass{}", snake_case));
|
||||
e.insert(result);
|
||||
result
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }`
|
||||
const fn c_name(name: &'static str) -> &'static str {
|
||||
// FIXME Simplify the implementation once more `str` methods get const-stable.
|
||||
// and inline into call site
|
||||
let bytes = name.as_bytes();
|
||||
let mut i = bytes.len();
|
||||
while i > 0 && bytes[i - 1] != b':' {
|
||||
i = i - 1;
|
||||
}
|
||||
let (_, bytes) = bytes.split_at(i);
|
||||
match std::str::from_utf8(bytes) {
|
||||
Ok(name) => name,
|
||||
Err(_) => name,
|
||||
}
|
||||
}
|
||||
|
||||
/// A streamlined trait that you can implement to create a pass; the
|
||||
/// pass will be named after the type, and it will consist of a main
|
||||
/// loop that goes over each available MIR and applies `run_pass`.
|
||||
pub(super) trait MirPass<'tcx> {
|
||||
fn name(&self) -> &'static str {
|
||||
// FIXME Simplify the implementation once more `str` methods get const-stable.
|
||||
// See copypaste in `MirLint`
|
||||
const {
|
||||
let name = std::any::type_name::<Self>();
|
||||
c_name(name)
|
||||
}
|
||||
}
|
||||
|
||||
fn profiler_name(&self) -> &'static str {
|
||||
to_profiler_name(self.name())
|
||||
}
|
||||
|
||||
/// Returns `true` if this pass is enabled with the current combination of compiler flags.
|
||||
fn is_enabled(&self, _sess: &Session) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
|
||||
|
||||
fn is_mir_dump_enabled(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Just like `MirPass`, except it cannot mutate `Body`, and MIR dumping is
|
||||
/// disabled (via the `Lint` adapter).
|
||||
pub(super) trait MirLint<'tcx> {
|
||||
fn name(&self) -> &'static str {
|
||||
// FIXME Simplify the implementation once more `str` methods get const-stable.
|
||||
// See copypaste in `MirPass`
|
||||
const {
|
||||
let name = std::any::type_name::<Self>();
|
||||
rustc_middle::util::common::c_name(name)
|
||||
c_name(name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +106,7 @@ pub trait MirLint<'tcx> {
|
||||
|
||||
/// An adapter for `MirLint`s that implements `MirPass`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Lint<T>(pub T);
|
||||
pub(super) struct Lint<T>(pub T);
|
||||
|
||||
impl<'tcx, T> MirPass<'tcx> for Lint<T>
|
||||
where
|
||||
@ -49,7 +129,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WithMinOptLevel<T>(pub u32, pub T);
|
||||
pub(super) struct WithMinOptLevel<T>(pub u32, pub T);
|
||||
|
||||
impl<'tcx, T> MirPass<'tcx> for WithMinOptLevel<T>
|
||||
where
|
||||
@ -70,7 +150,7 @@ where
|
||||
|
||||
/// Run the sequence of passes without validating the MIR after each pass. The MIR is still
|
||||
/// validated at the end.
|
||||
pub fn run_passes_no_validate<'tcx>(
|
||||
pub(super) fn run_passes_no_validate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &mut Body<'tcx>,
|
||||
passes: &[&dyn MirPass<'tcx>],
|
||||
@ -80,7 +160,7 @@ pub fn run_passes_no_validate<'tcx>(
|
||||
}
|
||||
|
||||
/// The optional `phase_change` is applied after executing all the passes, if present
|
||||
pub fn run_passes<'tcx>(
|
||||
pub(super) fn run_passes<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &mut Body<'tcx>,
|
||||
passes: &[&dyn MirPass<'tcx>],
|
||||
@ -89,7 +169,7 @@ pub fn run_passes<'tcx>(
|
||||
run_passes_inner(tcx, body, passes, phase_change, true);
|
||||
}
|
||||
|
||||
pub fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool
|
||||
pub(super) fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool
|
||||
where
|
||||
P: MirPass<'tcx> + ?Sized,
|
||||
{
|
||||
@ -185,11 +265,11 @@ fn run_passes_inner<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
|
||||
pub(super) fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
|
||||
validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body);
|
||||
}
|
||||
|
||||
pub fn dump_mir_for_pass<'tcx>(
|
||||
pub(super) fn dump_mir_for_pass<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
pass_name: &str,
|
||||
@ -205,7 +285,7 @@ pub fn dump_mir_for_pass<'tcx>(
|
||||
);
|
||||
}
|
||||
|
||||
pub fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
pub(super) fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
assert_eq!(body.pass_count, 0);
|
||||
mir::dump_mir(tcx, true, body.phase.name(), &"after", body, |_, _| Ok(()))
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ use rustc_session::Session;
|
||||
/// `IndexVec`, unless that successor is a back-edge (such as from a loop).
|
||||
pub struct ReorderBasicBlocks;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks {
|
||||
impl<'tcx> crate::MirPass<'tcx> for ReorderBasicBlocks {
|
||||
fn is_enabled(&self, _session: &Session) -> bool {
|
||||
false
|
||||
}
|
||||
@ -45,7 +45,7 @@ impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks {
|
||||
/// (Does not reorder arguments nor the [`RETURN_PLACE`].)
|
||||
pub struct ReorderLocals;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for ReorderLocals {
|
||||
impl<'tcx> crate::MirPass<'tcx> for ReorderLocals {
|
||||
fn is_enabled(&self, _session: &Session) -> bool {
|
||||
false
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ pub struct PromoteTemps<'tcx> {
|
||||
pub promoted_fragments: Cell<IndexVec<Promoted, Body<'tcx>>>,
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
|
||||
impl<'tcx> crate::MirPass<'tcx> for PromoteTemps<'tcx> {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
// There's not really any point in promoting errorful MIR.
|
||||
//
|
||||
|
@ -72,7 +72,7 @@ use crate::ssa::{SsaLocals, StorageLiveLocals};
|
||||
/// so we perform all the possible instantiations without removing the `_1 = &_2` statement.
|
||||
pub struct ReferencePropagation;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for ReferencePropagation {
|
||||
impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 2
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use tracing::debug;
|
||||
/// terrible code for these.
|
||||
pub struct RemoveNoopLandingPads;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
|
||||
impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.panic_strategy() != PanicStrategy::Abort
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use tracing::trace;
|
||||
|
||||
pub struct RemovePlaceMention;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for RemovePlaceMention {
|
||||
impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
!sess.opts.unstable_opts.mir_keep_place_mention
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use tracing::trace;
|
||||
|
||||
pub struct RemoveStorageMarkers;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers {
|
||||
impl<'tcx> crate::MirPass<'tcx> for RemoveStorageMarkers {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() > 0 && !sess.emit_lifetime_markers()
|
||||
}
|
||||
|
@ -6,8 +6,6 @@ use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
|
||||
use rustc_mir_dataflow::{move_path_children_matching, Analysis, MaybeReachable};
|
||||
use rustc_target::abi::FieldIdx;
|
||||
|
||||
use crate::MirPass;
|
||||
|
||||
/// Removes `Drop` terminators whose target is known to be uninitialized at
|
||||
/// that point.
|
||||
///
|
||||
@ -18,7 +16,7 @@ use crate::MirPass;
|
||||
/// [#90770]: https://github.com/rust-lang/rust/issues/90770
|
||||
pub struct RemoveUninitDrops;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
|
||||
impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let param_env = tcx.param_env(body.source.def_id());
|
||||
let move_data =
|
||||
|
@ -12,7 +12,7 @@ use super::simplify::simplify_cfg;
|
||||
|
||||
pub struct RemoveUnneededDrops;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
|
||||
impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
trace!("Running RemoveUnneededDrops on {:?}", body.source);
|
||||
|
||||
|
@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
pub struct RemoveZsts;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for RemoveZsts {
|
||||
impl<'tcx> crate::MirPass<'tcx> for RemoveZsts {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() > 0
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
pub struct RevealAll;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for RevealAll {
|
||||
impl<'tcx> crate::MirPass<'tcx> for RevealAll {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
|
||||
RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body);
|
||||
|
11
compiler/rustc_mir_transform/src/sanity_check.rs
Normal file
11
compiler/rustc_mir_transform/src/sanity_check.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use rustc_middle::mir::Body;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_mir_dataflow::rustc_peek::sanity_check;
|
||||
|
||||
pub(super) struct SanityCheck;
|
||||
|
||||
impl<'tcx> crate::MirLint<'tcx> for SanityCheck {
|
||||
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
sanity_check(tcx, body);
|
||||
}
|
||||
}
|
@ -74,7 +74,7 @@ pub(crate) fn simplify_cfg(body: &mut Body<'_>) {
|
||||
body.basic_blocks_mut().raw.shrink_to_fit();
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for SimplifyCfg {
|
||||
impl<'tcx> crate::MirPass<'tcx> for SimplifyCfg {
|
||||
fn name(&self) -> &'static str {
|
||||
self.name()
|
||||
}
|
||||
@ -366,7 +366,7 @@ pub enum SimplifyLocals {
|
||||
Final,
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
|
||||
impl<'tcx> crate::MirPass<'tcx> for SimplifyLocals {
|
||||
fn name(&self) -> &'static str {
|
||||
match &self {
|
||||
SimplifyLocals::BeforeConstProp => "SimplifyLocals-before-const-prop",
|
||||
|
@ -7,7 +7,7 @@ pub enum SimplifyConstCondition {
|
||||
Final,
|
||||
}
|
||||
/// A pass that replaces a branch with a goto when its condition is known.
|
||||
impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
|
||||
impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
|
||||
fn name(&self) -> &'static str {
|
||||
match self {
|
||||
SimplifyConstCondition::AfterConstProp => "SimplifyConstCondition-after-const-prop",
|
||||
|
@ -9,8 +9,6 @@ use rustc_middle::mir::{
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use tracing::trace;
|
||||
|
||||
use super::MirPass;
|
||||
|
||||
/// Pass to convert `if` conditions on integrals into switches on the integral.
|
||||
/// For an example, it turns something like
|
||||
///
|
||||
@ -27,7 +25,7 @@ use super::MirPass;
|
||||
/// ```
|
||||
pub struct SimplifyComparisonIntegral;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
|
||||
impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() > 0
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ use rustc_middle::ty::TyCtxt;
|
||||
/// needed to do that too, including updating the debug info.
|
||||
pub struct SingleUseConsts;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for SingleUseConsts {
|
||||
impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() > 0
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use tracing::{debug, instrument};
|
||||
|
||||
pub struct ScalarReplacementOfAggregates;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates {
|
||||
impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 2
|
||||
}
|
||||
|
@ -12,8 +12,6 @@ use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_target::abi::{Abi, Variants};
|
||||
use tracing::trace;
|
||||
|
||||
use crate::MirPass;
|
||||
|
||||
pub struct UnreachableEnumBranching;
|
||||
|
||||
fn get_discriminant_local(terminator: &TerminatorKind<'_>) -> Option<Local> {
|
||||
@ -74,7 +72,7 @@ fn variant_discriminants<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for UnreachableEnumBranching {
|
||||
impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() > 0
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use rustc_target::abi::Size;
|
||||
|
||||
pub struct UnreachablePropagation;
|
||||
|
||||
impl MirPass<'_> for UnreachablePropagation {
|
||||
impl crate::MirPass<'_> for UnreachablePropagation {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
// Enable only under -Zmir-opt-level=2 as this can make programs less debuggable.
|
||||
sess.mir_opt_level() >= 2
|
||||
|
@ -36,7 +36,7 @@ pub struct Validator {
|
||||
pub mir_phase: MirPhase,
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for Validator {
|
||||
impl<'tcx> crate::MirPass<'tcx> for Validator {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
// FIXME(JakobDegen): These bodies never instantiated in codegend anyway, so it's not
|
||||
// terribly important that they pass the validator. However, I think other passes might
|
||||
|
@ -304,6 +304,11 @@ where
|
||||
|
||||
let mut candidates = vec![];
|
||||
|
||||
if self.solver_mode() == SolverMode::Coherence {
|
||||
if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) {
|
||||
return vec![candidate];
|
||||
}
|
||||
}
|
||||
self.assemble_impl_candidates(goal, &mut candidates);
|
||||
|
||||
self.assemble_builtin_impl_candidates(goal, &mut candidates);
|
||||
@ -314,11 +319,8 @@ where
|
||||
|
||||
self.assemble_param_env_candidates(goal, &mut candidates);
|
||||
|
||||
match self.solver_mode() {
|
||||
SolverMode::Normal => self.discard_impls_shadowed_by_env(goal, &mut candidates),
|
||||
SolverMode::Coherence => {
|
||||
self.assemble_coherence_unknowable_candidates(goal, &mut candidates)
|
||||
}
|
||||
if self.solver_mode() == SolverMode::Normal {
|
||||
self.discard_impls_shadowed_by_env(goal, &mut candidates);
|
||||
}
|
||||
|
||||
candidates
|
||||
@ -682,38 +684,34 @@ where
|
||||
/// also consider impls which may get added in a downstream or sibling crate
|
||||
/// or which an upstream impl may add in a minor release.
|
||||
///
|
||||
/// To do so we add an ambiguous candidate in case such an unknown impl could
|
||||
/// apply to the current goal.
|
||||
/// To do so we return a single ambiguous candidate in case such an unknown
|
||||
/// impl could apply to the current goal.
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
fn assemble_coherence_unknowable_candidates<G: GoalKind<D>>(
|
||||
fn consider_coherence_unknowable_candidate<G: GoalKind<D>>(
|
||||
&mut self,
|
||||
goal: Goal<I, G>,
|
||||
candidates: &mut Vec<Candidate<I>>,
|
||||
) {
|
||||
let cx = self.cx();
|
||||
|
||||
candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(
|
||||
|ecx| {
|
||||
let trait_ref = goal.predicate.trait_ref(cx);
|
||||
if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
|
||||
Err(NoSolution)
|
||||
} else {
|
||||
// While the trait bound itself may be unknowable, we may be able to
|
||||
// prove that a super trait is not implemented. For this, we recursively
|
||||
// prove the super trait bounds of the current goal.
|
||||
//
|
||||
// We skip the goal itself as that one would cycle.
|
||||
let predicate: I::Predicate = trait_ref.upcast(cx);
|
||||
ecx.add_goals(
|
||||
GoalSource::Misc,
|
||||
elaborate::elaborate(cx, [predicate])
|
||||
.skip(1)
|
||||
.map(|predicate| goal.with(cx, predicate)),
|
||||
);
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
}
|
||||
},
|
||||
))
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(|ecx| {
|
||||
let cx = ecx.cx();
|
||||
let trait_ref = goal.predicate.trait_ref(cx);
|
||||
if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
|
||||
Err(NoSolution)
|
||||
} else {
|
||||
// While the trait bound itself may be unknowable, we may be able to
|
||||
// prove that a super trait is not implemented. For this, we recursively
|
||||
// prove the super trait bounds of the current goal.
|
||||
//
|
||||
// We skip the goal itself as that one would cycle.
|
||||
let predicate: I::Predicate = trait_ref.upcast(cx);
|
||||
ecx.add_goals(
|
||||
GoalSource::Misc,
|
||||
elaborate::elaborate(cx, [predicate])
|
||||
.skip(1)
|
||||
.map(|predicate| goal.with(cx, predicate)),
|
||||
);
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// If there's a where-bound for the current goal, do not use any impl candidates
|
||||
|
@ -19,17 +19,25 @@ use crate::errors::{
|
||||
OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
|
||||
};
|
||||
|
||||
/// The context in which a block is encountered.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum Context {
|
||||
Normal,
|
||||
Fn,
|
||||
Loop(hir::LoopSource),
|
||||
Closure(Span),
|
||||
Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource },
|
||||
Coroutine {
|
||||
coroutine_span: Span,
|
||||
kind: hir::CoroutineDesugaring,
|
||||
source: hir::CoroutineSource,
|
||||
},
|
||||
UnlabeledBlock(Span),
|
||||
UnlabeledIfBlock(Span),
|
||||
LabeledBlock,
|
||||
Constant,
|
||||
/// E.g. The labeled block inside `['_'; 'block: { break 'block 1 + 2; }]`.
|
||||
AnonConst,
|
||||
/// E.g. `const { ... }`.
|
||||
ConstBlock,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -90,11 +98,11 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) {
|
||||
self.with_context(Constant, |v| intravisit::walk_anon_const(v, c));
|
||||
self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c));
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) {
|
||||
self.with_context(Constant, |v| intravisit::walk_inline_const(v, c));
|
||||
self.with_context(ConstBlock, |v| intravisit::walk_inline_const(v, c));
|
||||
}
|
||||
|
||||
fn visit_fn(
|
||||
@ -128,7 +136,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||
&& matches!(
|
||||
ck_loop.cx_stack.last(),
|
||||
Some(&Normal)
|
||||
| Some(&Constant)
|
||||
| Some(&AnonConst)
|
||||
| Some(&UnlabeledBlock(_))
|
||||
| Some(&UnlabeledIfBlock(_))
|
||||
)
|
||||
@ -175,14 +183,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||
hir::ExprKind::Block(ref b, Some(_label)) => {
|
||||
self.with_context(LabeledBlock, |v| v.visit_block(b));
|
||||
}
|
||||
hir::ExprKind::Block(ref b, None) if matches!(self.cx_stack.last(), Some(&Fn)) => {
|
||||
hir::ExprKind::Block(ref b, None)
|
||||
if matches!(self.cx_stack.last(), Some(&Fn) | Some(&ConstBlock)) =>
|
||||
{
|
||||
self.with_context(Normal, |v| v.visit_block(b));
|
||||
}
|
||||
hir::ExprKind::Block(ref b, None)
|
||||
if matches!(
|
||||
self.cx_stack.last(),
|
||||
Some(&Normal) | Some(&Constant) | Some(&UnlabeledBlock(_))
|
||||
) =>
|
||||
hir::ExprKind::Block(
|
||||
ref b @ hir::Block { rules: hir::BlockCheckMode::DefaultBlock, .. },
|
||||
None,
|
||||
) if matches!(
|
||||
self.cx_stack.last(),
|
||||
Some(&Normal) | Some(&AnonConst) | Some(&UnlabeledBlock(_))
|
||||
) =>
|
||||
{
|
||||
self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b));
|
||||
}
|
||||
@ -353,7 +365,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
||||
UnlabeledIfBlock(_) if br_cx_kind == BreakContextKind::Break => {
|
||||
self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1);
|
||||
}
|
||||
Normal | Constant | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) => {
|
||||
Normal | AnonConst | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) | ConstBlock => {
|
||||
self.sess.dcx().emit_err(OutsideLoop {
|
||||
spans: vec![span],
|
||||
name: &br_cx_kind.to_string(),
|
||||
@ -365,7 +377,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
||||
}
|
||||
|
||||
fn require_label_in_labeled_block(
|
||||
&mut self,
|
||||
&self,
|
||||
span: Span,
|
||||
label: &Destination,
|
||||
cf_type: &str,
|
||||
@ -380,7 +392,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
||||
false
|
||||
}
|
||||
|
||||
fn report_outside_loop_error(&mut self) {
|
||||
fn report_outside_loop_error(&self) {
|
||||
for (s, block) in &self.block_breaks {
|
||||
self.sess.dcx().emit_err(OutsideLoop {
|
||||
spans: block.spans.clone(),
|
||||
|
@ -229,17 +229,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
||||
} else {
|
||||
let variant =
|
||||
&adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
|
||||
|
||||
// In the cases of either a `#[non_exhaustive]` field list or a non-public
|
||||
// field, we skip uninhabited fields in order not to reveal the
|
||||
// uninhabitedness of the whole variant.
|
||||
let is_non_exhaustive =
|
||||
variant.is_field_list_non_exhaustive() && !adt.did().is_local();
|
||||
let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
|
||||
let is_visible =
|
||||
adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
|
||||
let is_uninhabited = cx.is_uninhabited(*ty);
|
||||
let skip = is_uninhabited && (!is_visible || is_non_exhaustive);
|
||||
let skip = is_uninhabited && !is_visible;
|
||||
(ty, PrivateUninhabitedField(skip))
|
||||
});
|
||||
cx.dropless_arena.alloc_from_iter(tys)
|
||||
|
@ -2097,9 +2097,10 @@ pub struct TargetOptions {
|
||||
/// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults
|
||||
/// to "generic".
|
||||
pub cpu: StaticCow<str>,
|
||||
/// Default target features to pass to LLVM. These features will *always* be
|
||||
/// passed, and cannot be disabled even via `-C`. Corresponds to `llc
|
||||
/// -mattr=$features`.
|
||||
/// Default target features to pass to LLVM. These features overwrite
|
||||
/// `-Ctarget-cpu` but can be overwritten with `-Ctarget-features`.
|
||||
/// Corresponds to `llc -mattr=$features`.
|
||||
/// Note that these are LLVM feature names, not Rust feature names!
|
||||
pub features: StaticCow<str>,
|
||||
/// Direct or use GOT indirect to reference external data symbols
|
||||
pub direct_access_external_data: Option<bool>,
|
||||
|
@ -5023,24 +5023,32 @@ impl<'v> Visitor<'v> for AwaitsVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
/// Suggest a new type parameter name for diagnostic purposes.
|
||||
///
|
||||
/// `name` is the preferred name you'd like to suggest if it's not in use already.
|
||||
pub trait NextTypeParamName {
|
||||
fn next_type_param_name(&self, name: Option<&str>) -> String;
|
||||
}
|
||||
|
||||
impl NextTypeParamName for &[hir::GenericParam<'_>] {
|
||||
fn next_type_param_name(&self, name: Option<&str>) -> String {
|
||||
// This is the list of possible parameter names that we might suggest.
|
||||
// Type names are usually single letters in uppercase. So convert the first letter of input string to uppercase.
|
||||
let name = name.and_then(|n| n.chars().next()).map(|c| c.to_uppercase().to_string());
|
||||
let name = name.as_deref();
|
||||
|
||||
// This is the list of possible parameter names that we might suggest.
|
||||
let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"];
|
||||
let used_names = self
|
||||
|
||||
// Filter out used names based on `filter_fn`.
|
||||
let used_names: Vec<Symbol> = self
|
||||
.iter()
|
||||
.filter_map(|p| match p.name {
|
||||
.filter_map(|param| match param.name {
|
||||
hir::ParamName::Plain(ident) => Some(ident.name),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
.collect();
|
||||
|
||||
// Find a name from `possible_names` that is not in `used_names`.
|
||||
possible_names
|
||||
.iter()
|
||||
.find(|n| !used_names.contains(&Symbol::intern(n)))
|
||||
|
@ -29,6 +29,7 @@ use crate::infer::outlives::env::OutlivesEnvironment;
|
||||
use crate::infer::InferOk;
|
||||
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
||||
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::select::IntercrateAmbiguityCause;
|
||||
use crate::traits::{
|
||||
util, FulfillmentErrorCode, NormalizeExt, Obligation, ObligationCause, PredicateObligation,
|
||||
@ -624,14 +625,13 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
|
||||
// at ambiguous goals, as for others the coherence unknowable candidate
|
||||
// was irrelevant.
|
||||
match goal.result() {
|
||||
Ok(Certainty::Maybe(_)) => {}
|
||||
Ok(Certainty::Yes) | Err(NoSolution) => return,
|
||||
Ok(Certainty::Maybe(_)) => {}
|
||||
}
|
||||
|
||||
let Goal { param_env, predicate } = goal.goal();
|
||||
|
||||
// For bound predicates we simply call `infcx.enter_forall`
|
||||
// and then prove the resulting predicate as a nested goal.
|
||||
let Goal { param_env, predicate } = goal.goal();
|
||||
let trait_ref = match predicate.kind().no_bound_vars() {
|
||||
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
|
||||
Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)))
|
||||
@ -645,7 +645,11 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// Add ambiguity causes for reservation impls.
|
||||
if trait_ref.references_error() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut candidates = goal.candidates();
|
||||
for cand in goal.candidates() {
|
||||
if let inspect::ProbeKind::TraitCandidate {
|
||||
source: CandidateSource::Impl(def_id),
|
||||
@ -664,78 +668,68 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// Add ambiguity causes for unknowable goals.
|
||||
let mut ambiguity_cause = None;
|
||||
for cand in goal.candidates() {
|
||||
if let inspect::ProbeKind::TraitCandidate {
|
||||
source: CandidateSource::CoherenceUnknowable,
|
||||
result: Ok(_),
|
||||
} = cand.kind()
|
||||
{
|
||||
let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
|
||||
if matches!(ty.kind(), ty::Alias(..)) {
|
||||
let ocx = ObligationCtxt::new(infcx);
|
||||
ty = ocx
|
||||
.structurally_normalize(&ObligationCause::dummy(), param_env, ty)
|
||||
.map_err(|_| ())?;
|
||||
if !ocx.select_where_possible().is_empty() {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
Ok(ty)
|
||||
};
|
||||
// We also look for unknowable candidates. In case a goal is unknowable, there's
|
||||
// always exactly 1 candidate.
|
||||
let Some(cand) = candidates.pop() else {
|
||||
return;
|
||||
};
|
||||
|
||||
infcx.probe(|_| {
|
||||
match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) {
|
||||
Err(()) => {}
|
||||
Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
|
||||
Ok(Err(conflict)) => {
|
||||
if !trait_ref.references_error() {
|
||||
// Normalize the trait ref for diagnostics, ignoring any errors if this fails.
|
||||
let trait_ref =
|
||||
deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
|
||||
let inspect::ProbeKind::TraitCandidate {
|
||||
source: CandidateSource::CoherenceUnknowable,
|
||||
result: Ok(_),
|
||||
} = cand.kind()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
|
||||
ambiguity_cause = Some(match conflict {
|
||||
Conflict::Upstream => {
|
||||
IntercrateAmbiguityCause::UpstreamCrateUpdate {
|
||||
trait_ref,
|
||||
self_ty,
|
||||
}
|
||||
}
|
||||
Conflict::Downstream => {
|
||||
IntercrateAmbiguityCause::DownstreamCrate {
|
||||
trait_ref,
|
||||
self_ty,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
match cand.result() {
|
||||
// We only add an ambiguity cause if the goal would otherwise
|
||||
// result in an error.
|
||||
//
|
||||
// FIXME: While this matches the behavior of the
|
||||
// old solver, it is not the only way in which the unknowable
|
||||
// candidates *weaken* coherence, they can also force otherwise
|
||||
// successful normalization to be ambiguous.
|
||||
Ok(Certainty::Maybe(_) | Certainty::Yes) => {
|
||||
ambiguity_cause = None;
|
||||
break;
|
||||
}
|
||||
Err(NoSolution) => continue,
|
||||
let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
|
||||
if matches!(ty.kind(), ty::Alias(..)) {
|
||||
let ocx = ObligationCtxt::new(infcx);
|
||||
ty = ocx
|
||||
.structurally_normalize(&ObligationCause::dummy(), param_env, ty)
|
||||
.map_err(|_| ())?;
|
||||
if !ocx.select_where_possible().is_empty() {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(ty)
|
||||
};
|
||||
|
||||
if let Some(ambiguity_cause) = ambiguity_cause {
|
||||
self.causes.insert(ambiguity_cause);
|
||||
}
|
||||
infcx.probe(|_| {
|
||||
let conflict = match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) {
|
||||
Err(()) => return,
|
||||
Ok(Ok(())) => {
|
||||
warn!("expected an unknowable trait ref: {trait_ref:?}");
|
||||
return;
|
||||
}
|
||||
Ok(Err(conflict)) => conflict,
|
||||
};
|
||||
|
||||
// It is only relevant that a goal is unknowable if it would have otherwise
|
||||
// failed.
|
||||
let non_intercrate_infcx = infcx.fork_with_intercrate(false);
|
||||
if non_intercrate_infcx.predicate_may_hold(&Obligation::new(
|
||||
infcx.tcx,
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
predicate,
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Normalize the trait ref for diagnostics, ignoring any errors if this fails.
|
||||
let trait_ref = deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
|
||||
self.causes.insert(match conflict {
|
||||
Conflict::Upstream => {
|
||||
IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty }
|
||||
}
|
||||
Conflict::Downstream => {
|
||||
IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty }
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ pub enum Reveal {
|
||||
All,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SolverMode {
|
||||
/// Ordinary trait solving, using everywhere except for coherence.
|
||||
Normal,
|
||||
|
@ -195,3 +195,120 @@ conditionally compile code instead. This is notably different to the way native
|
||||
platforms such as x86\_64 work, and this is due to the fact that WebAssembly
|
||||
binaries must only contain code the engine understands. Native binaries work so
|
||||
long as the CPU doesn't execute unknown code dynamically at runtime.
|
||||
|
||||
## Broken `extern "C"` ABI
|
||||
|
||||
This target has what is considered a broken `extern "C"` ABI implementation at
|
||||
this time. Notably the same signature in Rust and C will compile to different
|
||||
WebAssembly functions and be incompatible. This is considered a bug and it will
|
||||
be fixed in a future version of Rust.
|
||||
|
||||
For example this Rust code:
|
||||
|
||||
```rust,ignore (does-not-link)
|
||||
#[repr(C)]
|
||||
struct MyPair {
|
||||
a: u32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn take_my_pair(pair: MyPair) -> u32;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn call_c() -> u32 {
|
||||
take_my_pair(MyPair { a: 1, b: 2 })
|
||||
}
|
||||
```
|
||||
|
||||
compiles to a WebAssembly module that looks like:
|
||||
|
||||
```wasm
|
||||
(module
|
||||
(import "env" "take_my_pair" (func $take_my_pair (param i32 i32) (result i32)))
|
||||
(func $call_c
|
||||
i32.const 1
|
||||
i32.const 2
|
||||
call $take_my_pair
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
The function when defined in C, however, looks like
|
||||
|
||||
```c
|
||||
struct my_pair {
|
||||
unsigned a;
|
||||
unsigned b;
|
||||
};
|
||||
|
||||
unsigned take_my_pair(struct my_pair pair) {
|
||||
return pair.a + pair.b;
|
||||
}
|
||||
```
|
||||
|
||||
```wasm
|
||||
(module
|
||||
(import "env" "__linear_memory" (memory 0))
|
||||
(func $take_my_pair (param i32) (result i32)
|
||||
local.get 0
|
||||
i32.load offset=4
|
||||
local.get 0
|
||||
i32.load
|
||||
i32.add
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
Notice how Rust thinks `take_my_pair` takes two `i32` parameters but C thinks it
|
||||
only takes one.
|
||||
|
||||
The correct definition of the `extern "C"` ABI for WebAssembly is located in the
|
||||
[WebAssembly/tool-conventions](https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md)
|
||||
repository. The `wasm32-unknown-unknown` target (and only this target, not other
|
||||
WebAssembly targets Rust support) does not correctly follow this document.
|
||||
|
||||
Example issues in the Rust repository about this bug are:
|
||||
|
||||
* [#115666](https://github.com/rust-lang/rust/issues/115666)
|
||||
* [#129486](https://github.com/rust-lang/rust/issues/129486)
|
||||
|
||||
This current state of the `wasm32-unknown-unknown` backend is due to an
|
||||
unfortunate accident which got relied on. The `wasm-bindgen` project prior to
|
||||
0.2.89 was incompatible with the "correct" definition of `extern "C"` and it was
|
||||
seen as not worth the tradeoff of breaking `wasm-bindgen` historically to fix
|
||||
this issue in the compiler.
|
||||
|
||||
Thanks to the heroic efforts of many involved in this, however, `wasm-bindgen`
|
||||
0.2.89 and later are compatible with the correct definition of `extern "C"` and
|
||||
the nightly compiler currently supports a `-Zwasm-c-abi` implemented in
|
||||
[#117919](https://github.com/rust-lang/rust/pull/117919). This nightly-only flag
|
||||
can be used to indicate whether the spec-defined version of `extern "C"` should
|
||||
be used instead of the "legacy" version of
|
||||
whatever-the-Rust-target-originally-implemented. For example using the above
|
||||
code you can see (lightly edited for clarity):
|
||||
|
||||
```shell
|
||||
$ rustc +nightly -Zwasm-c-abi=spec foo.rs --target wasm32-unknown-unknown --crate-type lib --emit obj -O
|
||||
$ wasm-tools print foo.o
|
||||
(module
|
||||
(import "env" "take_my_pair" (func $take_my_pair (param i32) (result i32)))
|
||||
(func $call_c (result i32)
|
||||
;; ...
|
||||
)
|
||||
;; ...
|
||||
)
|
||||
```
|
||||
|
||||
which shows that the C and Rust definitions of the same function now agree like
|
||||
they should.
|
||||
|
||||
The `-Zwasm-c-abi` compiler flag is tracked in
|
||||
[#122532](https://github.com/rust-lang/rust/issues/122532) and a lint was
|
||||
implemented in [#117918](https://github.com/rust-lang/rust/issues/117918) to
|
||||
help warn users about the transition if they're using `wasm-bindgen` 0.2.88 or
|
||||
prior. The current plan is to, in the future, switch `-Zwasm-c-api=spec` to
|
||||
being the default. Some time after that the `-Zwasm-c-abi` flag and the
|
||||
"legacy" implementation will all be removed. During this process users on a
|
||||
sufficiently updated version of `wasm-bindgen` should not experience breakage.
|
||||
|
@ -7,7 +7,7 @@ LL |
|
||||
LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::Item)`
|
||||
|
|
||||
= note: upstream crates may add a new impl of trait `std::clone::Clone` for type `(MyType,)` in future versions
|
||||
= note: upstream crates may add a new impl of trait `std::clone::Clone` for type `std::boxed::Box<(MyType,)>` in future versions
|
||||
= note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
@ -18,6 +18,6 @@ impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
|
||||
//~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>,
|
||||
//~| NOTE conflicting implementation for `(Box<(MyType,)>,
|
||||
//~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
|
||||
//[next]~| NOTE upstream crates may add a new impl of trait `std::clone::Clone` for type `(MyType,)` in future versions
|
||||
//[next]~| NOTE upstream crates may add a new impl of trait `std::clone::Clone` for type `std::boxed::Box<(MyType,)>` in future versions
|
||||
|
||||
fn main() {}
|
||||
|
@ -4,7 +4,15 @@ error[E0782]: trait objects must include the `dyn` keyword
|
||||
LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
help: add `dyn` keyword before this trait
|
||||
help: use a new generic type parameter, constrained by `SomeTrait`
|
||||
|
|
||||
LL | fn function<T: SomeTrait>(x: &T, y: Box<SomeTrait>) {
|
||||
| ++++++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn function(x: &impl SomeTrait, y: Box<SomeTrait>) {
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `SomeTrait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn function(x: &dyn SomeTrait, y: Box<SomeTrait>) {
|
||||
| +++
|
||||
|
@ -0,0 +1,25 @@
|
||||
fn main() {
|
||||
let _ = ['a'; { break 2; 1 }];
|
||||
//~^ ERROR `break` outside of a loop or labeled block
|
||||
//~| HELP consider labeling this block to be able to break within it
|
||||
|
||||
const {
|
||||
{
|
||||
//~^ HELP consider labeling this block to be able to break within it
|
||||
break;
|
||||
//~^ ERROR `break` outside of a loop or labeled block
|
||||
}
|
||||
};
|
||||
|
||||
const {
|
||||
break;
|
||||
//~^ ERROR `break` outside of a loop or labeled block
|
||||
};
|
||||
|
||||
{
|
||||
const {
|
||||
break;
|
||||
//~^ ERROR `break` outside of a loop or labeled block
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
error[E0268]: `break` outside of a loop or labeled block
|
||||
--> $DIR/break-inside-inline-const-issue-128604.rs:15:9
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^ cannot `break` outside of a loop or labeled block
|
||||
|
||||
error[E0268]: `break` outside of a loop or labeled block
|
||||
--> $DIR/break-inside-inline-const-issue-128604.rs:21:13
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^ cannot `break` outside of a loop or labeled block
|
||||
|
||||
error[E0268]: `break` outside of a loop or labeled block
|
||||
--> $DIR/break-inside-inline-const-issue-128604.rs:2:21
|
||||
|
|
||||
LL | let _ = ['a'; { break 2; 1 }];
|
||||
| ^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||
|
|
||||
help: consider labeling this block to be able to break within it
|
||||
|
|
||||
LL | let _ = ['a'; 'block: { break 'block 2; 1 }];
|
||||
| +++++++ ++++++
|
||||
|
||||
error[E0268]: `break` outside of a loop or labeled block
|
||||
--> $DIR/break-inside-inline-const-issue-128604.rs:9:13
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^ cannot `break` outside of a loop or labeled block
|
||||
|
|
||||
help: consider labeling this block to be able to break within it
|
||||
|
|
||||
LL ~ 'block: {
|
||||
LL |
|
||||
LL ~ break 'block;
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0268`.
|
@ -0,0 +1,142 @@
|
||||
//@ edition:2021
|
||||
|
||||
trait Trait {}
|
||||
|
||||
struct IceCream;
|
||||
|
||||
impl IceCream {
|
||||
fn foo(_: &Trait) {}
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
|
||||
fn bar(self, _: &'a Trait) {}
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
//~| ERROR: use of undeclared lifetime name
|
||||
|
||||
fn alice<'a>(&self, _: &Trait) {}
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
|
||||
fn bob<'a>(_: &'a Trait) {}
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
|
||||
fn cat() -> &Trait {
|
||||
//~^ ERROR: missing lifetime specifier
|
||||
//~| ERROR: trait objects must include the `dyn` keyword
|
||||
&Type
|
||||
}
|
||||
|
||||
fn dog<'a>() -> &Trait {
|
||||
//~^ ERROR: missing lifetime specifier
|
||||
//~| ERROR: trait objects must include the `dyn` keyword
|
||||
&Type
|
||||
}
|
||||
|
||||
fn kitten() -> &'a Trait {
|
||||
//~^ ERROR: use of undeclared lifetime name
|
||||
//~| ERROR: trait objects must include the `dyn` keyword
|
||||
&Type
|
||||
}
|
||||
|
||||
fn puppy<'a>() -> &'a Trait {
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
&Type
|
||||
}
|
||||
|
||||
fn parrot() -> &mut Trait {
|
||||
//~^ ERROR: missing lifetime specifier
|
||||
//~| ERROR: trait objects must include the `dyn` keyword
|
||||
&mut Type
|
||||
//~^ ERROR: cannot return reference to temporary value
|
||||
}
|
||||
}
|
||||
|
||||
trait Sing {
|
||||
fn foo(_: &Trait);
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
|
||||
fn bar(_: &'a Trait);
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
//~| ERROR: use of undeclared lifetime name
|
||||
|
||||
fn alice<'a>(_: &Trait);
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
|
||||
fn bob<'a>(_: &'a Trait);
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
|
||||
fn cat() -> &Trait;
|
||||
//~^ ERROR: missing lifetime specifier
|
||||
//~| ERROR: trait objects must include the `dyn` keyword
|
||||
|
||||
fn dog<'a>() -> &Trait {
|
||||
//~^ ERROR: missing lifetime specifier
|
||||
//~| ERROR: trait objects must include the `dyn` keyword
|
||||
&Type
|
||||
}
|
||||
|
||||
fn kitten() -> &'a Trait {
|
||||
//~^ ERROR: use of undeclared lifetime name
|
||||
//~| ERROR: trait objects must include the `dyn` keyword
|
||||
&Type
|
||||
}
|
||||
|
||||
fn puppy<'a>() -> &'a Trait {
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
&Type
|
||||
}
|
||||
|
||||
fn parrot() -> &mut Trait {
|
||||
//~^ ERROR: missing lifetime specifier
|
||||
//~| ERROR: trait objects must include the `dyn` keyword
|
||||
&mut Type
|
||||
//~^ ERROR: cannot return reference to temporary value
|
||||
}
|
||||
}
|
||||
|
||||
fn foo(_: &Trait) {}
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
|
||||
fn bar(_: &'a Trait) {}
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
//~| ERROR: use of undeclared lifetime name
|
||||
|
||||
fn alice<'a>(_: &Trait) {}
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
|
||||
fn bob<'a>(_: &'a Trait) {}
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
|
||||
struct Type;
|
||||
|
||||
impl Trait for Type {}
|
||||
|
||||
fn cat() -> &Trait {
|
||||
//~^ ERROR: missing lifetime specifier
|
||||
//~| ERROR: trait objects must include the `dyn` keyword
|
||||
&Type
|
||||
}
|
||||
|
||||
fn dog<'a>() -> &Trait {
|
||||
//~^ ERROR: missing lifetime specifier
|
||||
//~| ERROR: trait objects must include the `dyn` keyword
|
||||
&Type
|
||||
}
|
||||
|
||||
fn kitten() -> &'a Trait {
|
||||
//~^ ERROR: use of undeclared lifetime name
|
||||
//~| ERROR: trait objects must include the `dyn` keyword
|
||||
&Type
|
||||
}
|
||||
|
||||
fn puppy<'a>() -> &'a Trait {
|
||||
//~^ ERROR: trait objects must include the `dyn` keyword
|
||||
&Type
|
||||
}
|
||||
|
||||
fn parrot() -> &mut Trait {
|
||||
//~^ ERROR: missing lifetime specifier
|
||||
//~| ERROR: trait objects must include the `dyn` keyword
|
||||
&mut Type
|
||||
//~^ ERROR: cannot return reference to temporary value
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,673 @@
|
||||
error[E0261]: use of undeclared lifetime name `'a`
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:11:22
|
||||
|
|
||||
LL | fn bar(self, _: &'a Trait) {}
|
||||
| ^^ undeclared lifetime
|
||||
|
|
||||
help: consider introducing lifetime `'a` here
|
||||
|
|
||||
LL | fn bar<'a>(self, _: &'a Trait) {}
|
||||
| ++++
|
||||
help: consider introducing lifetime `'a` here
|
||||
|
|
||||
LL | impl<'a> IceCream {
|
||||
| ++++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:21:17
|
||||
|
|
||||
LL | fn cat() -> &Trait {
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
|
||||
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
||||
|
|
||||
LL | fn cat() -> &'static Trait {
|
||||
| +++++++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:27:21
|
||||
|
|
||||
LL | fn dog<'a>() -> &Trait {
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
|
||||
help: consider using the `'a` lifetime
|
||||
|
|
||||
LL | fn dog<'a>() -> &'a Trait {
|
||||
| ++
|
||||
|
||||
error[E0261]: use of undeclared lifetime name `'a`
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:33:21
|
||||
|
|
||||
LL | fn kitten() -> &'a Trait {
|
||||
| ^^ undeclared lifetime
|
||||
|
|
||||
help: consider introducing lifetime `'a` here
|
||||
|
|
||||
LL | fn kitten<'a>() -> &'a Trait {
|
||||
| ++++
|
||||
help: consider introducing lifetime `'a` here
|
||||
|
|
||||
LL | impl<'a> IceCream {
|
||||
| ++++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:44:20
|
||||
|
|
||||
LL | fn parrot() -> &mut Trait {
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
|
||||
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
||||
|
|
||||
LL | fn parrot() -> &'static mut Trait {
|
||||
| +++++++
|
||||
|
||||
error[E0261]: use of undeclared lifetime name `'a`
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:56:16
|
||||
|
|
||||
LL | fn bar(_: &'a Trait);
|
||||
| ^^ undeclared lifetime
|
||||
|
|
||||
help: consider introducing lifetime `'a` here
|
||||
|
|
||||
LL | fn bar<'a>(_: &'a Trait);
|
||||
| ++++
|
||||
help: consider introducing lifetime `'a` here
|
||||
|
|
||||
LL | trait Sing<'a> {
|
||||
| ++++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:66:17
|
||||
|
|
||||
LL | fn cat() -> &Trait;
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
|
||||
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
||||
|
|
||||
LL | fn cat() -> &'static Trait;
|
||||
| +++++++
|
||||
help: instead, you are more likely to want to return an owned value
|
||||
|
|
||||
LL - fn cat() -> &Trait;
|
||||
LL + fn cat() -> Trait;
|
||||
|
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:70:21
|
||||
|
|
||||
LL | fn dog<'a>() -> &Trait {
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
|
||||
help: consider using the `'a` lifetime
|
||||
|
|
||||
LL | fn dog<'a>() -> &'a Trait {
|
||||
| ++
|
||||
|
||||
error[E0261]: use of undeclared lifetime name `'a`
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:76:21
|
||||
|
|
||||
LL | fn kitten() -> &'a Trait {
|
||||
| ^^ undeclared lifetime
|
||||
|
|
||||
help: consider introducing lifetime `'a` here
|
||||
|
|
||||
LL | fn kitten<'a>() -> &'a Trait {
|
||||
| ++++
|
||||
help: consider introducing lifetime `'a` here
|
||||
|
|
||||
LL | trait Sing<'a> {
|
||||
| ++++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:87:20
|
||||
|
|
||||
LL | fn parrot() -> &mut Trait {
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
|
||||
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
||||
|
|
||||
LL | fn parrot() -> &'static mut Trait {
|
||||
| +++++++
|
||||
|
||||
error[E0261]: use of undeclared lifetime name `'a`
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:98:12
|
||||
|
|
||||
LL | fn bar(_: &'a Trait) {}
|
||||
| - ^^ undeclared lifetime
|
||||
| |
|
||||
| help: consider introducing lifetime `'a` here: `<'a>`
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:112:13
|
||||
|
|
||||
LL | fn cat() -> &Trait {
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
|
||||
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
||||
|
|
||||
LL | fn cat() -> &'static Trait {
|
||||
| +++++++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:118:17
|
||||
|
|
||||
LL | fn dog<'a>() -> &Trait {
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
|
||||
help: consider using the `'a` lifetime
|
||||
|
|
||||
LL | fn dog<'a>() -> &'a Trait {
|
||||
| ++
|
||||
|
||||
error[E0261]: use of undeclared lifetime name `'a`
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:124:17
|
||||
|
|
||||
LL | fn kitten() -> &'a Trait {
|
||||
| - ^^ undeclared lifetime
|
||||
| |
|
||||
| help: consider introducing lifetime `'a` here: `<'a>`
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:135:16
|
||||
|
|
||||
LL | fn parrot() -> &mut Trait {
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
|
||||
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
||||
|
|
||||
LL | fn parrot() -> &'static mut Trait {
|
||||
| +++++++
|
||||
|
||||
error[E0515]: cannot return reference to temporary value
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:47:9
|
||||
|
|
||||
LL | &mut Type
|
||||
| ^^^^^----
|
||||
| | |
|
||||
| | temporary value created here
|
||||
| returns a reference to data owned by the current function
|
||||
|
||||
error[E0515]: cannot return reference to temporary value
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:90:9
|
||||
|
|
||||
LL | &mut Type
|
||||
| ^^^^^----
|
||||
| | |
|
||||
| | temporary value created here
|
||||
| returns a reference to data owned by the current function
|
||||
|
||||
error[E0515]: cannot return reference to temporary value
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:138:5
|
||||
|
|
||||
LL | &mut Type
|
||||
| ^^^^^----
|
||||
| | |
|
||||
| | temporary value created here
|
||||
| returns a reference to data owned by the current function
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:53:16
|
||||
|
|
||||
LL | fn foo(_: &Trait);
|
||||
| ^^^^^
|
||||
|
|
||||
help: use a new generic type parameter, constrained by `Trait`
|
||||
|
|
||||
LL | fn foo<T: Trait>(_: &T);
|
||||
| ++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn foo(_: &impl Trait);
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn foo(_: &dyn Trait);
|
||||
| +++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:56:19
|
||||
|
|
||||
LL | fn bar(_: &'a Trait);
|
||||
| ^^^^^
|
||||
|
|
||||
help: use a new generic type parameter, constrained by `Trait`
|
||||
|
|
||||
LL | fn bar<T: Trait>(_: &'a T);
|
||||
| ++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn bar(_: &'a impl Trait);
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn bar(_: &'a dyn Trait);
|
||||
| +++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:60:22
|
||||
|
|
||||
LL | fn alice<'a>(_: &Trait);
|
||||
| ^^^^^
|
||||
|
|
||||
help: use a new generic type parameter, constrained by `Trait`
|
||||
|
|
||||
LL | fn alice<'a, T: Trait>(_: &T);
|
||||
| ++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn alice<'a>(_: &impl Trait);
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn alice<'a>(_: &dyn Trait);
|
||||
| +++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:63:23
|
||||
|
|
||||
LL | fn bob<'a>(_: &'a Trait);
|
||||
| ^^^^^
|
||||
|
|
||||
help: use a new generic type parameter, constrained by `Trait`
|
||||
|
|
||||
LL | fn bob<'a, T: Trait>(_: &'a T);
|
||||
| ++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn bob<'a>(_: &'a impl Trait);
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn bob<'a>(_: &'a dyn Trait);
|
||||
| +++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:66:18
|
||||
|
|
||||
LL | fn cat() -> &Trait;
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn cat() -> &impl Trait;
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn cat() -> Box<dyn Trait>;
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:70:22
|
||||
|
|
||||
LL | fn dog<'a>() -> &Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn dog<'a>() -> &impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn dog<'a>() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:76:24
|
||||
|
|
||||
LL | fn kitten() -> &'a Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn kitten() -> &'a impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn kitten() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:82:27
|
||||
|
|
||||
LL | fn puppy<'a>() -> &'a Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn puppy<'a>() -> &'a impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn puppy<'a>() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:87:25
|
||||
|
|
||||
LL | fn parrot() -> &mut Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn parrot() -> &mut impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn parrot() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:95:12
|
||||
|
|
||||
LL | fn foo(_: &Trait) {}
|
||||
| ^^^^^
|
||||
|
|
||||
help: use a new generic type parameter, constrained by `Trait`
|
||||
|
|
||||
LL | fn foo<T: Trait>(_: &T) {}
|
||||
| ++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn foo(_: &impl Trait) {}
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn foo(_: &dyn Trait) {}
|
||||
| +++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:98:15
|
||||
|
|
||||
LL | fn bar(_: &'a Trait) {}
|
||||
| ^^^^^
|
||||
|
|
||||
help: use a new generic type parameter, constrained by `Trait`
|
||||
|
|
||||
LL | fn bar<T: Trait>(_: &'a T) {}
|
||||
| ++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn bar(_: &'a impl Trait) {}
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn bar(_: &'a dyn Trait) {}
|
||||
| +++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:102:18
|
||||
|
|
||||
LL | fn alice<'a>(_: &Trait) {}
|
||||
| ^^^^^
|
||||
|
|
||||
help: use a new generic type parameter, constrained by `Trait`
|
||||
|
|
||||
LL | fn alice<'a, T: Trait>(_: &T) {}
|
||||
| ++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn alice<'a>(_: &impl Trait) {}
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn alice<'a>(_: &dyn Trait) {}
|
||||
| +++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:105:19
|
||||
|
|
||||
LL | fn bob<'a>(_: &'a Trait) {}
|
||||
| ^^^^^
|
||||
|
|
||||
help: use a new generic type parameter, constrained by `Trait`
|
||||
|
|
||||
LL | fn bob<'a, T: Trait>(_: &'a T) {}
|
||||
| ++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn bob<'a>(_: &'a impl Trait) {}
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn bob<'a>(_: &'a dyn Trait) {}
|
||||
| +++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:112:14
|
||||
|
|
||||
LL | fn cat() -> &Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn cat() -> &impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn cat() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:118:18
|
||||
|
|
||||
LL | fn dog<'a>() -> &Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn dog<'a>() -> &impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn dog<'a>() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:124:20
|
||||
|
|
||||
LL | fn kitten() -> &'a Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn kitten() -> &'a impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn kitten() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:130:23
|
||||
|
|
||||
LL | fn puppy<'a>() -> &'a Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn puppy<'a>() -> &'a impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn puppy<'a>() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:135:21
|
||||
|
|
||||
LL | fn parrot() -> &mut Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn parrot() -> &mut impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn parrot() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:8:16
|
||||
|
|
||||
LL | fn foo(_: &Trait) {}
|
||||
| ^^^^^
|
||||
|
|
||||
help: use a new generic type parameter, constrained by `Trait`
|
||||
|
|
||||
LL | fn foo<T: Trait>(_: &T) {}
|
||||
| ++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn foo(_: &impl Trait) {}
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn foo(_: &dyn Trait) {}
|
||||
| +++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:11:25
|
||||
|
|
||||
LL | fn bar(self, _: &'a Trait) {}
|
||||
| ^^^^^
|
||||
|
|
||||
help: use a new generic type parameter, constrained by `Trait`
|
||||
|
|
||||
LL | fn bar<T: Trait>(self, _: &'a T) {}
|
||||
| ++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn bar(self, _: &'a impl Trait) {}
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn bar(self, _: &'a dyn Trait) {}
|
||||
| +++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:15:29
|
||||
|
|
||||
LL | fn alice<'a>(&self, _: &Trait) {}
|
||||
| ^^^^^
|
||||
|
|
||||
help: use a new generic type parameter, constrained by `Trait`
|
||||
|
|
||||
LL | fn alice<'a, T: Trait>(&self, _: &T) {}
|
||||
| ++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn alice<'a>(&self, _: &impl Trait) {}
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn alice<'a>(&self, _: &dyn Trait) {}
|
||||
| +++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:18:23
|
||||
|
|
||||
LL | fn bob<'a>(_: &'a Trait) {}
|
||||
| ^^^^^
|
||||
|
|
||||
help: use a new generic type parameter, constrained by `Trait`
|
||||
|
|
||||
LL | fn bob<'a, T: Trait>(_: &'a T) {}
|
||||
| ++++++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn bob<'a>(_: &'a impl Trait) {}
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn bob<'a>(_: &'a dyn Trait) {}
|
||||
| +++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:21:18
|
||||
|
|
||||
LL | fn cat() -> &Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn cat() -> &impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn cat() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:27:22
|
||||
|
|
||||
LL | fn dog<'a>() -> &Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn dog<'a>() -> &impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn dog<'a>() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:33:24
|
||||
|
|
||||
LL | fn kitten() -> &'a Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn kitten() -> &'a impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn kitten() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:39:27
|
||||
|
|
||||
LL | fn puppy<'a>() -> &'a Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn puppy<'a>() -> &'a impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn puppy<'a>() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:44:25
|
||||
|
|
||||
LL | fn parrot() -> &mut Trait {
|
||||
| ^^^^^
|
||||
|
|
||||
help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn parrot() -> &mut impl Trait {
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn parrot() -> Box<dyn Trait> {
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 45 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0106, E0261, E0515, E0782.
|
||||
For more information about an error, try `rustc --explain E0106`.
|
@ -7,11 +7,17 @@ pub enum UninhabitedEnum {
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct UninhabitedStruct {
|
||||
_priv: !,
|
||||
pub never: !,
|
||||
_priv: (),
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct UninhabitedTupleStruct(!);
|
||||
pub struct PrivatelyUninhabitedStruct {
|
||||
never: !,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct UninhabitedTupleStruct(pub !);
|
||||
|
||||
pub enum UninhabitedVariants {
|
||||
#[non_exhaustive] Tuple(!),
|
||||
|
@ -5,7 +5,7 @@ LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `IndirectUninhabitedEnum` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:26:1
|
||||
--> $DIR/auxiliary/uninhabited.rs:32:1
|
||||
|
|
||||
LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -24,7 +24,7 @@ LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `IndirectUninhabitedStruct` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:28:1
|
||||
--> $DIR/auxiliary/uninhabited.rs:34:1
|
||||
|
|
||||
LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -43,7 +43,7 @@ LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `IndirectUninhabitedTupleStruct` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:30:1
|
||||
--> $DIR/auxiliary/uninhabited.rs:36:1
|
||||
|
|
||||
LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -62,7 +62,7 @@ LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `IndirectUninhabitedVariants` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:32:1
|
||||
--> $DIR/auxiliary/uninhabited.rs:38:1
|
||||
|
|
||||
LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -5,7 +5,7 @@ LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `IndirectUninhabitedEnum` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:26:1
|
||||
--> $DIR/auxiliary/uninhabited.rs:32:1
|
||||
|
|
||||
LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -24,7 +24,7 @@ LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `IndirectUninhabitedStruct` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:28:1
|
||||
--> $DIR/auxiliary/uninhabited.rs:34:1
|
||||
|
|
||||
LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -43,7 +43,7 @@ LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `IndirectUninhabitedTupleStruct` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:30:1
|
||||
--> $DIR/auxiliary/uninhabited.rs:36:1
|
||||
|
|
||||
LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -62,7 +62,7 @@ LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `IndirectUninhabitedVariants` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:32:1
|
||||
--> $DIR/auxiliary/uninhabited.rs:38:1
|
||||
|
|
||||
LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -11,11 +11,12 @@ use uninhabited::PartiallyInhabitedVariants;
|
||||
|
||||
pub fn foo(x: PartiallyInhabitedVariants) {
|
||||
match x {
|
||||
PartiallyInhabitedVariants::Struct { .. } => {},
|
||||
PartiallyInhabitedVariants::Struct { .. } => {},
|
||||
PartiallyInhabitedVariants::Struct { .. } => {}
|
||||
//~^ ERROR unreachable pattern
|
||||
_ => {},
|
||||
PartiallyInhabitedVariants::Struct { .. } => {}
|
||||
//~^ ERROR unreachable pattern
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
fn main() {}
|
||||
|
@ -1,16 +1,23 @@
|
||||
error: unreachable pattern
|
||||
--> $DIR/issue-65157-repeated-match-arm.rs:15:9
|
||||
--> $DIR/issue-65157-repeated-match-arm.rs:14:9
|
||||
|
|
||||
LL | PartiallyInhabitedVariants::Struct { .. } => {},
|
||||
| ----------------------------------------- matches all the relevant values
|
||||
LL | PartiallyInhabitedVariants::Struct { .. } => {},
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this
|
||||
LL | PartiallyInhabitedVariants::Struct { .. } => {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `PartiallyInhabitedVariants` is uninhabited
|
||||
|
|
||||
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||
note: the lint level is defined here
|
||||
--> $DIR/issue-65157-repeated-match-arm.rs:2:9
|
||||
|
|
||||
LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: unreachable pattern
|
||||
--> $DIR/issue-65157-repeated-match-arm.rs:16:9
|
||||
|
|
||||
LL | PartiallyInhabitedVariants::Struct { .. } => {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `PartiallyInhabitedVariants` is uninhabited
|
||||
|
|
||||
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -3,12 +3,7 @@
|
||||
|
||||
extern crate uninhabited;
|
||||
|
||||
use uninhabited::{
|
||||
UninhabitedEnum,
|
||||
UninhabitedStruct,
|
||||
UninhabitedTupleStruct,
|
||||
UninhabitedVariants,
|
||||
};
|
||||
use uninhabited::*;
|
||||
|
||||
struct A;
|
||||
|
||||
@ -19,16 +14,20 @@ fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
|
||||
match x {} //~ ERROR non-exhaustive patterns
|
||||
}
|
||||
|
||||
fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
|
||||
fn empty_match_on_empty_struct(x: UninhabitedStruct) -> A {
|
||||
match x {}
|
||||
}
|
||||
|
||||
fn cannot_empty_match_on_privately_empty_struct(x: PrivatelyUninhabitedStruct) -> A {
|
||||
match x {} //~ ERROR non-exhaustive patterns
|
||||
}
|
||||
|
||||
fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
|
||||
match x {} //~ ERROR non-exhaustive patterns
|
||||
fn empty_match_on_empty_tuple_struct(x: UninhabitedTupleStruct) -> A {
|
||||
match x {}
|
||||
}
|
||||
|
||||
fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
|
||||
match x {} //~ ERROR non-exhaustive patterns
|
||||
fn empty_match_on_enum_with_empty_variants_struct(x: UninhabitedVariants) -> A {
|
||||
match x {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,15 +1,15 @@
|
||||
error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
|
||||
--> $DIR/match.rs:19:11
|
||||
error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty
|
||||
--> $DIR/match.rs:14:11
|
||||
|
|
||||
LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `UninhabitedEnum` defined here
|
||||
note: `uninhabited::UninhabitedEnum` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:5:1
|
||||
|
|
||||
LL | pub enum UninhabitedEnum {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive
|
||||
= note: the matched value is of type `uninhabited::UninhabitedEnum`, which is marked as non-exhaustive
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
||||
|
|
||||
LL ~ match x {
|
||||
@ -17,18 +17,18 @@ LL + _ => todo!(),
|
||||
LL ~ }
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
|
||||
--> $DIR/match.rs:23:11
|
||||
error[E0004]: non-exhaustive patterns: type `uninhabited::PrivatelyUninhabitedStruct` is non-empty
|
||||
--> $DIR/match.rs:22:11
|
||||
|
|
||||
LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `UninhabitedStruct` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:9:1
|
||||
note: `uninhabited::PrivatelyUninhabitedStruct` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:15:1
|
||||
|
|
||||
LL | pub struct UninhabitedStruct {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: the matched value is of type `UninhabitedStruct`
|
||||
LL | pub struct PrivatelyUninhabitedStruct {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: the matched value is of type `uninhabited::PrivatelyUninhabitedStruct`
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
||||
|
|
||||
LL ~ match x {
|
||||
@ -36,48 +36,6 @@ LL + _ => todo!(),
|
||||
LL ~ }
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
|
||||
--> $DIR/match.rs:27:11
|
||||
|
|
||||
LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `UninhabitedTupleStruct` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:14:1
|
||||
|
|
||||
LL | pub struct UninhabitedTupleStruct(!);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: the matched value is of type `UninhabitedTupleStruct`
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
||||
|
|
||||
LL ~ match x {
|
||||
LL + _ => todo!(),
|
||||
LL ~ }
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
|
||||
--> $DIR/match.rs:31:11
|
||||
|
|
||||
LL | match x {}
|
||||
| ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
|
||||
|
|
||||
note: `UninhabitedVariants` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:16:1
|
||||
|
|
||||
LL | pub enum UninhabitedVariants {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[non_exhaustive] Tuple(!),
|
||||
| ----- not covered
|
||||
LL | #[non_exhaustive] Struct { x: ! }
|
||||
| ------ not covered
|
||||
= note: the matched value is of type `UninhabitedVariants`
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
|
||||
|
|
||||
LL ~ match x {
|
||||
LL + UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(),
|
||||
LL ~ }
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0004`.
|
||||
|
@ -5,32 +5,28 @@
|
||||
extern crate uninhabited;
|
||||
|
||||
use uninhabited::{
|
||||
UninhabitedEnum,
|
||||
UninhabitedStruct,
|
||||
UninhabitedTupleStruct,
|
||||
UninhabitedVariants,
|
||||
UninhabitedEnum, UninhabitedStruct, UninhabitedTupleStruct, UninhabitedVariants,
|
||||
};
|
||||
|
||||
struct A;
|
||||
|
||||
// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate
|
||||
// will not compile. In particular, this enables the `exhaustive_patterns` feature as this can
|
||||
// change the branch used in the compiler to determine this.
|
||||
|
||||
fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
|
||||
// This test checks that non-exhaustive enums are never considered uninhabited outside their
|
||||
// defining crate, and non-exhaustive structs are considered uninhabited the same way as normal
|
||||
// ones.
|
||||
fn cannot_empty_match_on_non_exhaustive_empty_enum(x: UninhabitedEnum) -> A {
|
||||
match x {} //~ ERROR non-exhaustive patterns
|
||||
}
|
||||
|
||||
fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
|
||||
match x {} //~ ERROR non-exhaustive patterns
|
||||
fn empty_match_on_empty_struct(x: UninhabitedStruct) -> A {
|
||||
match x {}
|
||||
}
|
||||
|
||||
fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
|
||||
match x {} //~ ERROR non-exhaustive patterns
|
||||
fn empty_match_on_empty_tuple_struct(x: UninhabitedTupleStruct) -> A {
|
||||
match x {}
|
||||
}
|
||||
|
||||
fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
|
||||
match x {} //~ ERROR non-exhaustive patterns
|
||||
fn empty_match_on_enum_with_empty_variants_struct(x: UninhabitedVariants) -> A {
|
||||
match x {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty
|
||||
--> $DIR/match_with_exhaustive_patterns.rs:21:11
|
||||
--> $DIR/match_with_exhaustive_patterns.rs:17:11
|
||||
|
|
||||
LL | match x {}
|
||||
| ^
|
||||
@ -17,67 +17,6 @@ LL + _ => todo!(),
|
||||
LL ~ }
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
|
||||
--> $DIR/match_with_exhaustive_patterns.rs:25:11
|
||||
|
|
||||
LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `UninhabitedStruct` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:9:1
|
||||
|
|
||||
LL | pub struct UninhabitedStruct {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: the matched value is of type `UninhabitedStruct`
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
||||
|
|
||||
LL ~ match x {
|
||||
LL + _ => todo!(),
|
||||
LL ~ }
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
|
||||
--> $DIR/match_with_exhaustive_patterns.rs:29:11
|
||||
|
|
||||
LL | match x {}
|
||||
| ^
|
||||
|
|
||||
note: `UninhabitedTupleStruct` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:14:1
|
||||
|
|
||||
LL | pub struct UninhabitedTupleStruct(!);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: the matched value is of type `UninhabitedTupleStruct`
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
||||
|
|
||||
LL ~ match x {
|
||||
LL + _ => todo!(),
|
||||
LL ~ }
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
|
||||
--> $DIR/match_with_exhaustive_patterns.rs:33:11
|
||||
|
|
||||
LL | match x {}
|
||||
| ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
|
||||
|
|
||||
note: `UninhabitedVariants` defined here
|
||||
--> $DIR/auxiliary/uninhabited.rs:16:1
|
||||
|
|
||||
LL | pub enum UninhabitedVariants {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[non_exhaustive] Tuple(!),
|
||||
| ----- not covered
|
||||
LL | #[non_exhaustive] Struct { x: ! }
|
||||
| ------ not covered
|
||||
= note: the matched value is of type `UninhabitedVariants`
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
|
||||
|
|
||||
LL ~ match x {
|
||||
LL + UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(),
|
||||
LL ~ }
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0004`.
|
||||
|
@ -1,5 +1,4 @@
|
||||
//@ check-pass
|
||||
|
||||
#![deny(unreachable_patterns)]
|
||||
#![feature(never_type)]
|
||||
|
||||
@ -9,11 +8,12 @@ pub enum UninhabitedEnum {
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct UninhabitedStruct {
|
||||
_priv: !,
|
||||
pub never: !,
|
||||
_priv: (),
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct UninhabitedTupleStruct(!);
|
||||
pub struct UninhabitedTupleStruct(pub !);
|
||||
|
||||
pub enum UninhabitedVariants {
|
||||
#[non_exhaustive] Tuple(!),
|
||||
@ -22,24 +22,21 @@ pub enum UninhabitedVariants {
|
||||
|
||||
struct A;
|
||||
|
||||
// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate
|
||||
// will compile. In particular, this enables the `exhaustive_patterns` feature as this can
|
||||
// change the branch used in the compiler to determine this.
|
||||
// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648.
|
||||
|
||||
fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
|
||||
// This checks that `non_exhaustive` annotations do not affect exhaustiveness checking within the
|
||||
// defining crate.
|
||||
fn empty_match_on_empty_enum(x: UninhabitedEnum) -> A {
|
||||
match x {}
|
||||
}
|
||||
|
||||
fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
|
||||
fn empty_match_on_empty_struct(x: UninhabitedStruct) -> A {
|
||||
match x {}
|
||||
}
|
||||
|
||||
fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
|
||||
fn empty_match_on_empty_tuple_struct(x: UninhabitedTupleStruct) -> A {
|
||||
match x {}
|
||||
}
|
||||
|
||||
fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
|
||||
fn empty_match_on_enum_with_empty_variants_struct(x: UninhabitedVariants) -> A {
|
||||
match x {}
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,10 @@
|
||||
//@ aux-build:uninhabited.rs
|
||||
//@ build-pass (FIXME(62277): could be check-pass?)
|
||||
#![deny(unreachable_patterns)]
|
||||
|
||||
extern crate uninhabited;
|
||||
|
||||
use uninhabited::{
|
||||
PartiallyInhabitedVariants,
|
||||
UninhabitedEnum,
|
||||
UninhabitedStruct,
|
||||
UninhabitedTupleStruct,
|
||||
PartiallyInhabitedVariants, UninhabitedEnum, UninhabitedStruct, UninhabitedTupleStruct,
|
||||
UninhabitedVariants,
|
||||
};
|
||||
|
||||
@ -32,27 +28,26 @@ fn uninhabited_tuple_struct() -> Option<UninhabitedTupleStruct> {
|
||||
None
|
||||
}
|
||||
|
||||
// This test checks that non-exhaustive types that would normally be considered uninhabited within
|
||||
// the defining crate are not considered uninhabited from extern crates.
|
||||
|
||||
// This test checks that non-exhaustive enums are never considered uninhabited outside their
|
||||
// defining crate, and non-exhaustive structs are considered uninhabited the same way as normal
|
||||
// ones.
|
||||
fn main() {
|
||||
match uninhabited_enum() {
|
||||
Some(_x) => (), // This line would normally error.
|
||||
Some(_x) => (), // This would error without `non_exhaustive`
|
||||
None => (),
|
||||
}
|
||||
|
||||
match uninhabited_variant() {
|
||||
Some(_x) => (), // This line would normally error.
|
||||
Some(_x) => (), //~ ERROR unreachable
|
||||
None => (),
|
||||
}
|
||||
|
||||
// This line would normally error.
|
||||
while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {
|
||||
while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {} //~ ERROR unreachable
|
||||
|
||||
while let Some(_x) = uninhabited_struct() { //~ ERROR unreachable
|
||||
}
|
||||
|
||||
while let Some(_x) = uninhabited_struct() { // This line would normally error.
|
||||
}
|
||||
|
||||
while let Some(_x) = uninhabited_tuple_struct() { // This line would normally error.
|
||||
while let Some(_x) = uninhabited_tuple_struct() { //~ ERROR unreachable
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
error: unreachable pattern
|
||||
--> $DIR/patterns.rs:41:9
|
||||
|
|
||||
LL | Some(_x) => (),
|
||||
| ^^^^^^^^ matches no values because `UninhabitedVariants` is uninhabited
|
||||
|
|
||||
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||
note: the lint level is defined here
|
||||
--> $DIR/patterns.rs:2:9
|
||||
|
|
||||
LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/patterns.rs:46:15
|
||||
|
|
||||
LL | while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `!` is uninhabited
|
||||
|
|
||||
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/patterns.rs:48:15
|
||||
|
|
||||
LL | while let Some(_x) = uninhabited_struct() {
|
||||
| ^^^^^^^^ matches no values because `UninhabitedStruct` is uninhabited
|
||||
|
|
||||
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/patterns.rs:51:15
|
||||
|
|
||||
LL | while let Some(_x) = uninhabited_tuple_struct() {
|
||||
| ^^^^^^^^ matches no values because `UninhabitedTupleStruct` is uninhabited
|
||||
|
|
||||
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
@ -6,11 +6,12 @@ pub enum UninhabitedEnum {
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct UninhabitedTupleStruct(!);
|
||||
pub struct UninhabitedTupleStruct(pub !);
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct UninhabitedStruct {
|
||||
_priv: !,
|
||||
pub never: !,
|
||||
_priv: (),
|
||||
}
|
||||
|
||||
pub enum UninhabitedVariants {
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: unreachable pattern
|
||||
--> $DIR/patterns_same_crate.rs:51:9
|
||||
--> $DIR/patterns_same_crate.rs:52:9
|
||||
|
|
||||
LL | Some(_x) => (),
|
||||
| ^^^^^^^^ matches no values because `UninhabitedEnum` is uninhabited
|
||||
@ -12,7 +12,7 @@ LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/patterns_same_crate.rs:56:9
|
||||
--> $DIR/patterns_same_crate.rs:57:9
|
||||
|
|
||||
LL | Some(_x) => (),
|
||||
| ^^^^^^^^ matches no values because `UninhabitedVariants` is uninhabited
|
||||
@ -20,7 +20,7 @@ LL | Some(_x) => (),
|
||||
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/patterns_same_crate.rs:60:15
|
||||
--> $DIR/patterns_same_crate.rs:61:15
|
||||
|
|
||||
LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `!` is uninhabited
|
||||
@ -28,7 +28,7 @@ LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabite
|
||||
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/patterns_same_crate.rs:64:15
|
||||
--> $DIR/patterns_same_crate.rs:65:15
|
||||
|
|
||||
LL | while let Some(_x) = uninhabited_struct() {
|
||||
| ^^^^^^^^ matches no values because `UninhabitedStruct` is uninhabited
|
||||
@ -36,7 +36,7 @@ LL | while let Some(_x) = uninhabited_struct() {
|
||||
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/patterns_same_crate.rs:67:15
|
||||
--> $DIR/patterns_same_crate.rs:68:15
|
||||
|
|
||||
LL | while let Some(_x) = uninhabited_tuple_struct() {
|
||||
| ^^^^^^^^ matches no values because `UninhabitedTupleStruct` is uninhabited
|
||||
|
34
tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs
Normal file
34
tests/ui/unsafe/break-inside-unsafe-block-issue-128604.rs
Normal file
@ -0,0 +1,34 @@
|
||||
fn main() {
|
||||
let a = ["_"; unsafe { break; 1 + 2 }];
|
||||
//~^ ERROR `break` outside of a loop or labeled block
|
||||
|
||||
unsafe {
|
||||
{
|
||||
//~^ HELP consider labeling this block to be able to break within it
|
||||
break;
|
||||
//~^ ERROR `break` outside of a loop or labeled block
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
break;
|
||||
//~^ ERROR `break` outside of a loop or labeled block
|
||||
}
|
||||
|
||||
{
|
||||
//~^ HELP consider labeling this block to be able to break within it
|
||||
unsafe {
|
||||
break;
|
||||
//~^ ERROR `break` outside of a loop or labeled block
|
||||
}
|
||||
}
|
||||
|
||||
while 2 > 1 {
|
||||
unsafe {
|
||||
if true || false {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
error[E0268]: `break` outside of a loop or labeled block
|
||||
--> $DIR/break-inside-unsafe-block-issue-128604.rs:2:28
|
||||
|
|
||||
LL | let a = ["_"; unsafe { break; 1 + 2 }];
|
||||
| ^^^^^ cannot `break` outside of a loop or labeled block
|
||||
|
||||
error[E0268]: `break` outside of a loop or labeled block
|
||||
--> $DIR/break-inside-unsafe-block-issue-128604.rs:14:9
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^ cannot `break` outside of a loop or labeled block
|
||||
|
||||
error[E0268]: `break` outside of a loop or labeled block
|
||||
--> $DIR/break-inside-unsafe-block-issue-128604.rs:8:13
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^ cannot `break` outside of a loop or labeled block
|
||||
|
|
||||
help: consider labeling this block to be able to break within it
|
||||
|
|
||||
LL ~ 'block: {
|
||||
LL |
|
||||
LL ~ break 'block;
|
||||
|
|
||||
|
||||
error[E0268]: `break` outside of a loop or labeled block
|
||||
--> $DIR/break-inside-unsafe-block-issue-128604.rs:21:13
|
||||
|
|
||||
LL | break;
|
||||
| ^^^^^ cannot `break` outside of a loop or labeled block
|
||||
|
|
||||
help: consider labeling this block to be able to break within it
|
||||
|
|
||||
LL ~ 'block: {
|
||||
LL |
|
||||
LL | unsafe {
|
||||
LL ~ break 'block;
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0268`.
|
Loading…
Reference in New Issue
Block a user