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:
bors 2024-09-04 22:58:51 +00:00
commit 009e73825a
94 changed files with 1625 additions and 583 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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