1
Fork 0

Auto merge of #121036 - matthiaskrgr:rollup-ul05q8e, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #114877 (unstable-book: add quick-edit link)
 - #120548 (rustdoc: Fix handling of doc_auto_cfg feature for cfg attributes on glob reexport)
 - #120549 (modify alias-relate to also normalize ambiguous opaques)
 - #120959 (Remove good path delayed bugs)
 - #120978 (match lowering: simplify block creation)
 - #121019 (coverage: Simplify some parts of the coverage span refiner)
 - #121021 (Extend intra-doc link chapter in the rustdoc book)
 - #121031 (RustWrapper: adapt for coverage mapping API changes)

Failed merges:

 - #121014 (Remove `force_print_diagnostic`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-02-13 17:27:25 +00:00
commit a84bb95a1f
107 changed files with 1278 additions and 1192 deletions

View file

@ -288,7 +288,7 @@ impl<'tcx> fmt::Display for FrameInfo<'tcx> {
if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure { if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
write!(f, "inside closure") write!(f, "inside closure")
} else { } else {
// Note: this triggers a `good_path_delayed_bug` state, which means that if we ever // Note: this triggers a `must_produce_diag` state, which means that if we ever
// get here we must emit a diagnostic. We should never display a `FrameInfo` unless // get here we must emit a diagnostic. We should never display a `FrameInfo` unless
// we actually want to emit a warning or error to the user. // we actually want to emit a warning or error to the user.
write!(f, "inside `{}`", self.instance) write!(f, "inside `{}`", self.instance)
@ -304,7 +304,7 @@ impl<'tcx> FrameInfo<'tcx> {
errors::FrameNote { where_: "closure", span, instance: String::new(), times: 0 } errors::FrameNote { where_: "closure", span, instance: String::new(), times: 0 }
} else { } else {
let instance = format!("{}", self.instance); let instance = format!("{}", self.instance);
// Note: this triggers a `good_path_delayed_bug` state, which means that if we ever get // Note: this triggers a `must_produce_diag` state, which means that if we ever get
// here we must emit a diagnostic. We should never display a `FrameInfo` unless we // here we must emit a diagnostic. We should never display a `FrameInfo` unless we
// actually want to emit a warning or error to the user. // actually want to emit a warning or error to the user.
errors::FrameNote { where_: "instance", span, instance, times: 0 } errors::FrameNote { where_: "instance", span, instance, times: 0 }

View file

@ -376,7 +376,7 @@ impl From<Cow<'static, str>> for DiagnosticMessage {
} }
} }
/// A workaround for good_path_delayed_bug ICEs when formatting types in disabled lints. /// A workaround for must_produce_diag ICEs when formatting types in disabled lints.
/// ///
/// Delays formatting until `.into(): DiagnosticMessage` is used. /// Delays formatting until `.into(): DiagnosticMessage` is used.
pub struct DelayDm<F>(pub F); pub struct DelayDm<F>(pub F);

View file

@ -85,11 +85,7 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String {
/// Maps `Diagnostic::Level` to `snippet::AnnotationType` /// Maps `Diagnostic::Level` to `snippet::AnnotationType`
fn annotation_type_for_level(level: Level) -> AnnotationType { fn annotation_type_for_level(level: Level) -> AnnotationType {
match level { match level {
Level::Bug Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => AnnotationType::Error,
| Level::Fatal
| Level::Error
| Level::DelayedBug
| Level::GoodPathDelayedBug => AnnotationType::Error,
Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning, Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning,
Level::Note | Level::OnceNote => AnnotationType::Note, Level::Note | Level::OnceNote => AnnotationType::Note,
Level::Help | Level::OnceHelp => AnnotationType::Help, Level::Help | Level::OnceHelp => AnnotationType::Help,

View file

@ -237,8 +237,7 @@ impl Diagnostic {
match self.level { match self.level {
Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => true, Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => true,
Level::GoodPathDelayedBug Level::ForceWarning(_)
| Level::ForceWarning(_)
| Level::Warning | Level::Warning
| Level::Note | Level::Note
| Level::OnceNote | Level::OnceNote

View file

@ -435,7 +435,6 @@ struct DiagCtxtInner {
lint_err_guars: Vec<ErrorGuaranteed>, lint_err_guars: Vec<ErrorGuaranteed>,
/// The delayed bugs and their error guarantees. /// The delayed bugs and their error guarantees.
delayed_bugs: Vec<(DelayedDiagnostic, ErrorGuaranteed)>, delayed_bugs: Vec<(DelayedDiagnostic, ErrorGuaranteed)>,
good_path_delayed_bugs: Vec<DelayedDiagnostic>,
/// The number of stashed errors. Unlike the other counts, this can go up /// The number of stashed errors. Unlike the other counts, this can go up
/// and down, so it doesn't guarantee anything. /// and down, so it doesn't guarantee anything.
@ -446,13 +445,18 @@ struct DiagCtxtInner {
/// The warning count shown to the user at the end. /// The warning count shown to the user at the end.
deduplicated_warn_count: usize, deduplicated_warn_count: usize,
emitter: Box<DynEmitter>,
/// Must we produce a diagnostic to justify the use of the expensive
/// `trimmed_def_paths` function?
must_produce_diag: bool,
/// Has this diagnostic context printed any diagnostics? (I.e. has /// Has this diagnostic context printed any diagnostics? (I.e. has
/// `self.emitter.emit_diagnostic()` been called? /// `self.emitter.emit_diagnostic()` been called?
has_printed: bool, has_printed: bool,
emitter: Box<DynEmitter>,
/// This flag indicates that an expected diagnostic was emitted and suppressed. /// This flag indicates that an expected diagnostic was emitted and suppressed.
/// This is used for the `good_path_delayed_bugs` check. /// This is used for the `must_produce_diag` check.
suppressed_expected_diag: bool, suppressed_expected_diag: bool,
/// This set contains the code of all emitted diagnostics to avoid /// This set contains the code of all emitted diagnostics to avoid
@ -533,11 +537,6 @@ fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) {
pub static TRACK_DIAGNOSTIC: AtomicRef<fn(Diagnostic, &mut dyn FnMut(Diagnostic))> = pub static TRACK_DIAGNOSTIC: AtomicRef<fn(Diagnostic, &mut dyn FnMut(Diagnostic))> =
AtomicRef::new(&(default_track_diagnostic as _)); AtomicRef::new(&(default_track_diagnostic as _));
enum DelayedBugKind {
Normal,
GoodPath,
}
#[derive(Copy, Clone, Default)] #[derive(Copy, Clone, Default)]
pub struct DiagCtxtFlags { pub struct DiagCtxtFlags {
/// If false, warning-level lints are suppressed. /// If false, warning-level lints are suppressed.
@ -563,11 +562,16 @@ impl Drop for DiagCtxtInner {
self.emit_stashed_diagnostics(); self.emit_stashed_diagnostics();
if self.err_guars.is_empty() { if self.err_guars.is_empty() {
self.flush_delayed(DelayedBugKind::Normal) self.flush_delayed()
} }
if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() { if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
self.flush_delayed(DelayedBugKind::GoodPath); if self.must_produce_diag {
panic!(
"must_produce_diag: trimmed_def_paths called but no diagnostics emitted; \
use `DelayDm` for lints or `with_no_trimmed_paths` for debugging"
);
}
} }
if self.check_unstable_expect_diagnostics { if self.check_unstable_expect_diagnostics {
@ -609,12 +613,12 @@ impl DiagCtxt {
err_guars: Vec::new(), err_guars: Vec::new(),
lint_err_guars: Vec::new(), lint_err_guars: Vec::new(),
delayed_bugs: Vec::new(), delayed_bugs: Vec::new(),
good_path_delayed_bugs: Vec::new(),
stashed_err_count: 0, stashed_err_count: 0,
deduplicated_err_count: 0, deduplicated_err_count: 0,
deduplicated_warn_count: 0, deduplicated_warn_count: 0,
has_printed: false,
emitter, emitter,
must_produce_diag: false,
has_printed: false,
suppressed_expected_diag: false, suppressed_expected_diag: false,
taught_diagnostics: Default::default(), taught_diagnostics: Default::default(),
emitted_diagnostic_codes: Default::default(), emitted_diagnostic_codes: Default::default(),
@ -666,13 +670,14 @@ impl DiagCtxt {
inner.stashed_err_count = 0; inner.stashed_err_count = 0;
inner.deduplicated_err_count = 0; inner.deduplicated_err_count = 0;
inner.deduplicated_warn_count = 0; inner.deduplicated_warn_count = 0;
inner.must_produce_diag = false;
inner.has_printed = false; inner.has_printed = false;
inner.suppressed_expected_diag = false;
// actually free the underlying memory (which `clear` would not do) // actually free the underlying memory (which `clear` would not do)
inner.err_guars = Default::default(); inner.err_guars = Default::default();
inner.lint_err_guars = Default::default(); inner.lint_err_guars = Default::default();
inner.delayed_bugs = Default::default(); inner.delayed_bugs = Default::default();
inner.good_path_delayed_bugs = Default::default();
inner.taught_diagnostics = Default::default(); inner.taught_diagnostics = Default::default();
inner.emitted_diagnostic_codes = Default::default(); inner.emitted_diagnostic_codes = Default::default();
inner.emitted_diagnostics = Default::default(); inner.emitted_diagnostics = Default::default();
@ -934,7 +939,13 @@ impl DiagCtxt {
} }
pub fn flush_delayed(&self) { pub fn flush_delayed(&self) {
self.inner.borrow_mut().flush_delayed(DelayedBugKind::Normal); self.inner.borrow_mut().flush_delayed();
}
/// Used when trimmed_def_paths is called and we must produce a diagnostic
/// to justify its cost.
pub fn set_must_produce_diag(&self) {
self.inner.borrow_mut().must_produce_diag = true;
} }
} }
@ -1108,13 +1119,6 @@ impl DiagCtxt {
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).with_span(sp).emit() DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).with_span(sp).emit()
} }
/// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`.
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
#[track_caller]
pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit()
}
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
#[track_caller] #[track_caller]
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
@ -1266,19 +1270,17 @@ impl DiagCtxtInner {
if diagnostic.has_future_breakage() { if diagnostic.has_future_breakage() {
// Future breakages aren't emitted if they're Level::Allow, // Future breakages aren't emitted if they're Level::Allow,
// but they still need to be constructed and stashed below, // but they still need to be constructed and stashed below,
// so they'll trigger the good-path bug check. // so they'll trigger the must_produce_diag check.
self.suppressed_expected_diag = true; self.suppressed_expected_diag = true;
self.future_breakage_diagnostics.push(diagnostic.clone()); self.future_breakage_diagnostics.push(diagnostic.clone());
} }
if matches!(diagnostic.level, DelayedBug | GoodPathDelayedBug) if diagnostic.level == DelayedBug && self.flags.eagerly_emit_delayed_bugs {
&& self.flags.eagerly_emit_delayed_bugs
{
diagnostic.level = Error; diagnostic.level = Error;
} }
match diagnostic.level { match diagnostic.level {
// This must come after the possible promotion of `DelayedBug`/`GoodPathDelayedBug` to // This must come after the possible promotion of `DelayedBug` to
// `Error` above. // `Error` above.
Fatal | Error if self.treat_next_err_as_bug() => { Fatal | Error if self.treat_next_err_as_bug() => {
diagnostic.level = Bug; diagnostic.level = Bug;
@ -1297,12 +1299,6 @@ impl DiagCtxtInner {
.push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar)); .push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar));
return Some(guar); return Some(guar);
} }
GoodPathDelayedBug => {
let backtrace = std::backtrace::Backtrace::capture();
self.good_path_delayed_bugs
.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
return None;
}
Warning if !self.flags.can_emit_warnings => { Warning if !self.flags.can_emit_warnings => {
if diagnostic.has_future_breakage() { if diagnostic.has_future_breakage() {
(*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {}); (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
@ -1414,23 +1410,14 @@ impl DiagCtxtInner {
self.emit_diagnostic(Diagnostic::new(FailureNote, msg)); self.emit_diagnostic(Diagnostic::new(FailureNote, msg));
} }
fn flush_delayed(&mut self, kind: DelayedBugKind) { fn flush_delayed(&mut self) {
let (bugs, note1) = match kind { if self.delayed_bugs.is_empty() {
DelayedBugKind::Normal => (
std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(),
"no errors encountered even though delayed bugs were created",
),
DelayedBugKind::GoodPath => (
std::mem::take(&mut self.good_path_delayed_bugs),
"no warnings or errors encountered even though good path delayed bugs were created",
),
};
let note2 = "those delayed bugs will now be shown as internal compiler errors";
if bugs.is_empty() {
return; return;
} }
let bugs: Vec<_> =
std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect();
// If backtraces are enabled, also print the query stack // If backtraces are enabled, also print the query stack
let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(true, |x| &x != "0"); let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(true, |x| &x != "0");
for (i, bug) in bugs.into_iter().enumerate() { for (i, bug) in bugs.into_iter().enumerate() {
@ -1454,6 +1441,8 @@ impl DiagCtxtInner {
// frame them better (e.g. separate warnings from them). Also, // frame them better (e.g. separate warnings from them). Also,
// make it a note so it doesn't count as an error, because that // make it a note so it doesn't count as an error, because that
// could trigger `-Ztreat-err-as-bug`, which we don't want. // could trigger `-Ztreat-err-as-bug`, which we don't want.
let note1 = "no errors encountered even though delayed bugs were created";
let note2 = "those delayed bugs will now be shown as internal compiler errors";
self.emit_diagnostic(Diagnostic::new(Note, note1)); self.emit_diagnostic(Diagnostic::new(Note, note1));
self.emit_diagnostic(Diagnostic::new(Note, note2)); self.emit_diagnostic(Diagnostic::new(Note, note2));
} }
@ -1462,7 +1451,7 @@ impl DiagCtxtInner {
if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner }; if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner };
// "Undelay" the delayed bugs (into plain `Bug`s). // "Undelay" the delayed bugs (into plain `Bug`s).
if !matches!(bug.level, DelayedBug | GoodPathDelayedBug) { if bug.level != DelayedBug {
// NOTE(eddyb) not panicking here because we're already producing // NOTE(eddyb) not panicking here because we're already producing
// an ICE, and the more information the merrier. // an ICE, and the more information the merrier.
bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel { bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel {
@ -1534,7 +1523,6 @@ impl DelayedDiagnostic {
/// Fatal yes FatalAbort/FatalError(*) yes - - /// Fatal yes FatalAbort/FatalError(*) yes - -
/// Error yes ErrorGuaranteed yes - yes /// Error yes ErrorGuaranteed yes - yes
/// DelayedBug yes ErrorGuaranteed yes - - /// DelayedBug yes ErrorGuaranteed yes - -
/// GoodPathDelayedBug - () yes - -
/// ForceWarning - () yes - lint-only /// ForceWarning - () yes - lint-only
/// Warning - () yes yes yes /// Warning - () yes yes yes
/// Note - () rare yes - /// Note - () rare yes -
@ -1567,20 +1555,6 @@ pub enum Level {
/// that should only be reached when compiling erroneous code. /// that should only be reached when compiling erroneous code.
DelayedBug, DelayedBug,
/// Like `DelayedBug`, but weaker: lets you register an error without emitting it. If
/// compilation ends without any other diagnostics being emitted (and without an expected lint
/// being suppressed), this will be emitted as a bug. Otherwise, it will be silently dropped.
/// I.e. "expect other diagnostics are emitted (or suppressed)" semantics. Useful on code paths
/// that should only be reached when emitting diagnostics, e.g. for expensive one-time
/// diagnostic formatting operations.
///
/// FIXME(nnethercote) good path delayed bugs are semantically strange: if printed they produce
/// an ICE, but they don't satisfy `is_error` and they don't guarantee an error is emitted.
/// Plus there's the extra complication with expected (suppressed) lints. They have limited
/// use, and are used in very few places, and "good path" isn't a good name. It would be good
/// to remove them.
GoodPathDelayedBug,
/// A `force-warn` lint warning about the code being compiled. Does not prevent compilation /// A `force-warn` lint warning about the code being compiled. Does not prevent compilation
/// from finishing. /// from finishing.
/// ///
@ -1625,7 +1599,7 @@ impl Level {
fn color(self) -> ColorSpec { fn color(self) -> ColorSpec {
let mut spec = ColorSpec::new(); let mut spec = ColorSpec::new();
match self { match self {
Bug | Fatal | Error | DelayedBug | GoodPathDelayedBug => { Bug | Fatal | Error | DelayedBug => {
spec.set_fg(Some(Color::Red)).set_intense(true); spec.set_fg(Some(Color::Red)).set_intense(true);
} }
ForceWarning(_) | Warning => { ForceWarning(_) | Warning => {
@ -1645,7 +1619,7 @@ impl Level {
pub fn to_str(self) -> &'static str { pub fn to_str(self) -> &'static str {
match self { match self {
Bug | DelayedBug | GoodPathDelayedBug => "error: internal compiler error", Bug | DelayedBug => "error: internal compiler error",
Fatal | Error => "error", Fatal | Error => "error",
ForceWarning(_) | Warning => "warning", ForceWarning(_) | Warning => "warning",
Note | OnceNote => "note", Note | OnceNote => "note",
@ -1670,8 +1644,8 @@ impl Level {
// subdiagnostic message? // subdiagnostic message?
fn can_be_top_or_sub(&self) -> (bool, bool) { fn can_be_top_or_sub(&self) -> (bool, bool) {
match self { match self {
Bug | DelayedBug | Fatal | Error | GoodPathDelayedBug | ForceWarning(_) Bug | DelayedBug | Fatal | Error | ForceWarning(_) | FailureNote | Allow
| FailureNote | Allow | Expect(_) => (true, false), | Expect(_) => (true, false),
Warning | Note | Help => (true, true), Warning | Note | Help => (true, true),

View file

@ -304,6 +304,10 @@ fn typeck_with_fallback<'tcx>(
let typeck_results = fcx.resolve_type_vars_in_body(body); let typeck_results = fcx.resolve_type_vars_in_body(body);
// We clone the defined opaque types during writeback in the new solver
// because we have to use them during normalization.
let _ = fcx.infcx.take_opaque_types();
// Consistency check our TypeckResults instance can hold all ItemLocalIds // Consistency check our TypeckResults instance can hold all ItemLocalIds
// it will need to hold. // it will need to hold.
assert_eq!(typeck_results.hir_owner, id.owner); assert_eq!(typeck_results.hir_owner, id.owner);

View file

@ -562,7 +562,15 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn visit_opaque_types(&mut self) { fn visit_opaque_types(&mut self) {
let opaque_types = self.fcx.infcx.take_opaque_types(); // We clone the opaques instead of stealing them here as they are still used for
// normalization in the next generation trait solver.
//
// FIXME(-Znext-solver): Opaque types defined after this would simply get dropped
// at the end of typeck. While this seems unlikely to happen in practice this
// should still get fixed. Either by preventing writeback from defining new opaque
// types or by using this function at the end of writeback and running it as a
// fixpoint.
let opaque_types = self.fcx.infcx.clone_opaque_types();
for (opaque_type_key, decl) in opaque_types { for (opaque_type_key, decl) in opaque_types {
let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span); let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span); let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);

View file

@ -132,20 +132,6 @@ pub struct TypeErrCtxt<'a, 'tcx> {
Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>, Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
} }
impl Drop for TypeErrCtxt<'_, '_> {
fn drop(&mut self) {
if self.dcx().has_errors().is_some() {
// Ok, emitted an error.
} else {
// Didn't emit an error; maybe it was created but not yet emitted.
self.infcx
.tcx
.sess
.good_path_delayed_bug("used a `TypeErrCtxt` without raising an error or lint");
}
}
}
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
pub fn dcx(&self) -> &'tcx DiagCtxt { pub fn dcx(&self) -> &'tcx DiagCtxt {
self.infcx.tcx.dcx() self.infcx.tcx.dcx()

View file

@ -1325,6 +1325,12 @@ impl<'tcx> InferCtxt<'tcx> {
std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
} }
#[instrument(level = "debug", skip(self), ret)]
pub fn clone_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error);
self.inner.borrow().opaque_type_storage.opaque_types.clone()
}
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
self.resolve_vars_if_possible(t).to_string() self.resolve_vars_if_possible(t).to_string()
} }

View file

@ -139,7 +139,7 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer(
RustMappingRegions, NumMappingRegions)) { RustMappingRegions, NumMappingRegions)) {
MappingRegions.emplace_back( MappingRegions.emplace_back(
fromRust(Region.Count), fromRust(Region.FalseCount), fromRust(Region.Count), fromRust(Region.FalseCount),
#if LLVM_VERSION_GE(18, 0) #if LLVM_VERSION_GE(18, 0) && LLVM_VERSION_LT(19, 0)
coverage::CounterMappingRegion::MCDCParameters{}, coverage::CounterMappingRegion::MCDCParameters{},
#endif #endif
Region.FileID, Region.ExpandedFileID, Region.FileID, Region.ExpandedFileID,

View file

@ -3156,13 +3156,12 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
// this is pub to be able to intra-doc-link it // this is pub to be able to intra-doc-link it
pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap<Symbol> { pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap<Symbol> {
// Trimming paths is expensive and not optimized, since we expect it to only be used for error // Trimming paths is expensive and not optimized, since we expect it to only be used for error
// reporting. // reporting. Record the fact that we did it, so we can abort if we later found it was
// unnecessary.
// //
// For good paths causing this bug, the `rustc_middle::ty::print::with_no_trimmed_paths` // The `rustc_middle::ty::print::with_no_trimmed_paths` wrapper can be used to suppress this
// wrapper can be used to suppress this query, in exchange for full paths being formatted. // checking, in exchange for full paths being formatted.
tcx.sess.good_path_delayed_bug( tcx.sess.record_trimmed_def_paths();
"trimmed_def_paths constructed but no error emitted; use `DelayDm` for lints or `with_no_trimmed_paths` for debugging",
);
// Once constructed, unique namespace+symbol pairs will have a `Some(_)` entry, while // Once constructed, unique namespace+symbol pairs will have a `Some(_)` entry, while
// non-unique pairs will have a `None` entry. // non-unique pairs will have a `None` entry.

View file

@ -319,7 +319,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// them. // them.
let mut fake_borrows = match_has_guard.then(FxIndexSet::default); let mut fake_borrows = match_has_guard.then(FxIndexSet::default);
let mut otherwise = None; let otherwise_block = self.cfg.start_new_block();
// This will generate code to test scrutinee_place and // This will generate code to test scrutinee_place and
// branch to the appropriate arm block // branch to the appropriate arm block
@ -327,46 +327,44 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
match_start_span, match_start_span,
scrutinee_span, scrutinee_span,
block, block,
&mut otherwise, otherwise_block,
candidates, candidates,
&mut fake_borrows, &mut fake_borrows,
); );
if let Some(otherwise_block) = otherwise { // See the doc comment on `match_candidates` for why we may have an
// See the doc comment on `match_candidates` for why we may have an // otherwise block. Match checking will ensure this is actually
// otherwise block. Match checking will ensure this is actually // unreachable.
// unreachable. let source_info = self.source_info(scrutinee_span);
let source_info = self.source_info(scrutinee_span);
// Matching on a `scrutinee_place` with an uninhabited type doesn't // Matching on a `scrutinee_place` with an uninhabited type doesn't
// generate any memory reads by itself, and so if the place "expression" // generate any memory reads by itself, and so if the place "expression"
// contains unsafe operations like raw pointer dereferences or union // contains unsafe operations like raw pointer dereferences or union
// field projections, we wouldn't know to require an `unsafe` block // field projections, we wouldn't know to require an `unsafe` block
// around a `match` equivalent to `std::intrinsics::unreachable()`. // around a `match` equivalent to `std::intrinsics::unreachable()`.
// See issue #47412 for this hole being discovered in the wild. // See issue #47412 for this hole being discovered in the wild.
// //
// HACK(eddyb) Work around the above issue by adding a dummy inspection // HACK(eddyb) Work around the above issue by adding a dummy inspection
// of `scrutinee_place`, specifically by applying `ReadForMatch`. // of `scrutinee_place`, specifically by applying `ReadForMatch`.
// //
// NOTE: ReadForMatch also checks that the scrutinee is initialized. // NOTE: ReadForMatch also checks that the scrutinee is initialized.
// This is currently needed to not allow matching on an uninitialized, // This is currently needed to not allow matching on an uninitialized,
// uninhabited value. If we get never patterns, those will check that // uninhabited value. If we get never patterns, those will check that
// the place is initialized, and so this read would only be used to // the place is initialized, and so this read would only be used to
// check safety. // check safety.
let cause_matched_place = FakeReadCause::ForMatchedPlace(None); let cause_matched_place = FakeReadCause::ForMatchedPlace(None);
if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) {
self.cfg.push_fake_read( self.cfg.push_fake_read(
otherwise_block, otherwise_block,
source_info, source_info,
cause_matched_place, cause_matched_place,
scrutinee_place, scrutinee_place,
); );
}
self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable);
} }
self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable);
// Link each leaf candidate to the `pre_binding_block` of the next one. // Link each leaf candidate to the `pre_binding_block` of the next one.
let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None; let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None;
@ -1163,7 +1161,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
span: Span, span: Span,
scrutinee_span: Span, scrutinee_span: Span,
start_block: BasicBlock, start_block: BasicBlock,
otherwise_block: &mut Option<BasicBlock>, otherwise_block: BasicBlock,
candidates: &mut [&mut Candidate<'pat, 'tcx>], candidates: &mut [&mut Candidate<'pat, 'tcx>],
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>, fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) { ) {
@ -1210,7 +1208,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
span: Span, span: Span,
scrutinee_span: Span, scrutinee_span: Span,
start_block: BasicBlock, start_block: BasicBlock,
otherwise_block: &mut Option<BasicBlock>, otherwise_block: BasicBlock,
candidates: &mut [&mut Candidate<'_, 'tcx>], candidates: &mut [&mut Candidate<'_, 'tcx>],
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>, fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) { ) {
@ -1243,11 +1241,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// never reach this point. // never reach this point.
if unmatched_candidates.is_empty() { if unmatched_candidates.is_empty() {
let source_info = self.source_info(span); let source_info = self.source_info(span);
if let Some(otherwise) = *otherwise_block { self.cfg.goto(block, source_info, otherwise_block);
self.cfg.goto(block, source_info, otherwise);
} else {
*otherwise_block = Some(block);
}
return; return;
} }
@ -1428,7 +1422,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
scrutinee_span: Span, scrutinee_span: Span,
candidates: &mut [&mut Candidate<'_, 'tcx>], candidates: &mut [&mut Candidate<'_, 'tcx>],
block: BasicBlock, block: BasicBlock,
otherwise_block: &mut Option<BasicBlock>, otherwise_block: BasicBlock,
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>, fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) { ) {
let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap(); let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap();
@ -1453,7 +1447,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let match_pairs = mem::take(&mut first_candidate.match_pairs); let match_pairs = mem::take(&mut first_candidate.match_pairs);
first_candidate.pre_binding_block = Some(block); first_candidate.pre_binding_block = Some(block);
let mut otherwise = None; let remainder_start = self.cfg.start_new_block();
for match_pair in match_pairs { for match_pair in match_pairs {
let PatKind::Or { ref pats } = &match_pair.pattern.kind else { let PatKind::Or { ref pats } = &match_pair.pattern.kind else {
bug!("Or-patterns should have been sorted to the end"); bug!("Or-patterns should have been sorted to the end");
@ -1463,7 +1457,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
first_candidate.visit_leaves(|leaf_candidate| { first_candidate.visit_leaves(|leaf_candidate| {
self.test_or_pattern( self.test_or_pattern(
leaf_candidate, leaf_candidate,
&mut otherwise, remainder_start,
pats, pats,
or_span, or_span,
&match_pair.place, &match_pair.place,
@ -1472,8 +1466,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}); });
} }
let remainder_start = otherwise.unwrap_or_else(|| self.cfg.start_new_block());
self.match_candidates( self.match_candidates(
span, span,
scrutinee_span, scrutinee_span,
@ -1491,7 +1483,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn test_or_pattern<'pat>( fn test_or_pattern<'pat>(
&mut self, &mut self,
candidate: &mut Candidate<'pat, 'tcx>, candidate: &mut Candidate<'pat, 'tcx>,
otherwise: &mut Option<BasicBlock>, otherwise: BasicBlock,
pats: &'pat [Box<Pat<'tcx>>], pats: &'pat [Box<Pat<'tcx>>],
or_span: Span, or_span: Span,
place: &PlaceBuilder<'tcx>, place: &PlaceBuilder<'tcx>,
@ -1503,8 +1495,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard, self)) .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard, self))
.collect(); .collect();
let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect(); let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect();
let otherwise = if candidate.otherwise_block.is_some() { let otherwise = if let Some(otherwise_block) = candidate.otherwise_block {
&mut candidate.otherwise_block otherwise_block
} else { } else {
otherwise otherwise
}; };
@ -1680,8 +1672,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
span: Span, span: Span,
scrutinee_span: Span, scrutinee_span: Span,
mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
block: BasicBlock, start_block: BasicBlock,
otherwise_block: &mut Option<BasicBlock>, otherwise_block: BasicBlock,
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>, fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) { ) {
// extract the match-pair from the highest priority candidate // extract the match-pair from the highest priority candidate
@ -1749,12 +1741,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
debug!("untested_candidates: {}", candidates.len()); debug!("untested_candidates: {}", candidates.len());
// The block that we should branch to if none of the // The block that we should branch to if none of the
// `target_candidates` match. This is either the block where we // `target_candidates` match.
// start matching the untested candidates if there are any, let remainder_start = if !candidates.is_empty() {
// otherwise it's the `otherwise_block`. let remainder_start = self.cfg.start_new_block();
let remainder_start = &mut None; self.match_candidates(
let remainder_start = span,
if candidates.is_empty() { &mut *otherwise_block } else { remainder_start }; scrutinee_span,
remainder_start,
otherwise_block,
candidates,
fake_borrows,
);
remainder_start
} else {
otherwise_block
};
// For each outcome of test, process the candidates that still // For each outcome of test, process the candidates that still
// apply. Collect a list of blocks where control flow will // apply. Collect a list of blocks where control flow will
@ -1775,24 +1776,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
); );
candidate_start candidate_start
} else { } else {
*remainder_start.get_or_insert_with(|| self.cfg.start_new_block()) remainder_start
} }
}) })
.collect(); .collect();
if !candidates.is_empty() { // Perform the test, branching to one of N blocks.
let remainder_start = remainder_start.unwrap_or_else(|| self.cfg.start_new_block()); self.perform_test(span, scrutinee_span, start_block, &match_place, &test, target_blocks);
self.match_candidates(
span,
scrutinee_span,
remainder_start,
otherwise_block,
candidates,
fake_borrows,
);
}
self.perform_test(span, scrutinee_span, block, &match_place, &test, target_blocks);
} }
/// Determine the fake borrows that are needed from a set of places that /// Determine the fake borrows that are needed from a set of places that

View file

@ -1,9 +1,10 @@
use rustc_data_structures::graph::WithNumNodes; use rustc_data_structures::graph::WithNumNodes;
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_middle::mir; use rustc_middle::mir;
use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_span::{BytePos, Span};
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
use crate::coverage::spans::from_mir::SpanFromMir;
use crate::coverage::ExtractedHirInfo; use crate::coverage::ExtractedHirInfo;
mod from_mir; mod from_mir;
@ -61,7 +62,7 @@ pub(super) fn generate_coverage_spans(
basic_coverage_blocks, basic_coverage_blocks,
); );
let coverage_spans = SpansRefiner::refine_sorted_spans(basic_coverage_blocks, sorted_spans); let coverage_spans = SpansRefiner::refine_sorted_spans(basic_coverage_blocks, sorted_spans);
mappings.extend(coverage_spans.into_iter().map(|CoverageSpan { bcb, span, .. }| { mappings.extend(coverage_spans.into_iter().map(|RefinedCovspan { bcb, span, .. }| {
// Each span produced by the generator represents an ordinary code region. // Each span produced by the generator represents an ordinary code region.
BcbMapping { kind: BcbMappingKind::Code(bcb), span } BcbMapping { kind: BcbMappingKind::Code(bcb), span }
})); }));
@ -85,18 +86,36 @@ pub(super) fn generate_coverage_spans(
Some(CoverageSpans { bcb_has_mappings, mappings }) Some(CoverageSpans { bcb_has_mappings, mappings })
} }
/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that #[derive(Debug)]
/// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s. struct CurrCovspan {
/// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent /// This is used as the basis for [`PrevCovspan::original_span`], so it must
/// transforms can combine adjacent `Span`s and `CoverageSpan` from the same BCB, merging the /// not be modified.
/// `merged_spans` vectors, and the `Span`s to cover the extent of the combined `Span`s. span: Span,
/// bcb: BasicCoverageBlock,
/// Note: A span merged into another CoverageSpan may come from a `BasicBlock` that is_closure: bool,
/// is not part of the `CoverageSpan` bcb if the statement was included because it's `Span` matches }
/// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock`
/// `dominates()` the `BasicBlock`s in this `CoverageSpan`. impl CurrCovspan {
#[derive(Debug, Clone)] fn new(span: Span, bcb: BasicCoverageBlock, is_closure: bool) -> Self {
struct CoverageSpan { Self { span, bcb, is_closure }
}
fn into_prev(self) -> PrevCovspan {
let Self { span, bcb, is_closure } = self;
PrevCovspan { original_span: span, span, bcb, merged_spans: vec![span], is_closure }
}
fn into_refined(self) -> RefinedCovspan {
// This is only called in cases where `curr` is a closure span that has
// been carved out of `prev`.
debug_assert!(self.is_closure);
self.into_prev().into_refined()
}
}
#[derive(Debug)]
struct PrevCovspan {
original_span: Span,
span: Span, span: Span,
bcb: BasicCoverageBlock, bcb: BasicCoverageBlock,
/// List of all the original spans from MIR that have been merged into this /// List of all the original spans from MIR that have been merged into this
@ -105,37 +124,82 @@ struct CoverageSpan {
is_closure: bool, is_closure: bool,
} }
impl CoverageSpan { impl PrevCovspan {
fn new(span: Span, bcb: BasicCoverageBlock, is_closure: bool) -> Self { fn is_mergeable(&self, other: &CurrCovspan) -> bool {
Self { span, bcb, merged_spans: vec![span], is_closure } self.bcb == other.bcb && !self.is_closure && !other.is_closure
} }
pub fn merge_from(&mut self, other: &Self) { fn merge_from(&mut self, other: &CurrCovspan) {
debug_assert!(self.is_mergeable(other)); debug_assert!(self.is_mergeable(other));
self.span = self.span.to(other.span); self.span = self.span.to(other.span);
self.merged_spans.extend_from_slice(&other.merged_spans); self.merged_spans.push(other.span);
} }
pub fn cutoff_statements_at(&mut self, cutoff_pos: BytePos) { fn cutoff_statements_at(&mut self, cutoff_pos: BytePos) {
self.merged_spans.retain(|span| span.hi() <= cutoff_pos); self.merged_spans.retain(|span| span.hi() <= cutoff_pos);
if let Some(max_hi) = self.merged_spans.iter().map(|span| span.hi()).max() { if let Some(max_hi) = self.merged_spans.iter().map(|span| span.hi()).max() {
self.span = self.span.with_hi(max_hi); self.span = self.span.with_hi(max_hi);
} }
} }
#[inline] fn into_dup(self) -> DuplicateCovspan {
pub fn is_mergeable(&self, other: &Self) -> bool { let Self { original_span, span, bcb, merged_spans: _, is_closure } = self;
self.is_in_same_bcb(other) && !(self.is_closure || other.is_closure) // Only unmodified spans end up in `pending_dups`.
debug_assert_eq!(original_span, span);
DuplicateCovspan { span, bcb, is_closure }
} }
#[inline] fn refined_copy(&self) -> RefinedCovspan {
pub fn is_in_same_bcb(&self, other: &Self) -> bool { let &Self { original_span: _, span, bcb, merged_spans: _, is_closure } = self;
self.bcb == other.bcb RefinedCovspan { span, bcb, is_closure }
}
fn into_refined(self) -> RefinedCovspan {
self.refined_copy()
} }
} }
/// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a #[derive(Debug)]
/// minimal set of `CoverageSpan`s, using the BCB CFG to determine where it is safe and useful to: struct DuplicateCovspan {
span: Span,
bcb: BasicCoverageBlock,
is_closure: bool,
}
impl DuplicateCovspan {
/// Returns a copy of this covspan, as a [`RefinedCovspan`].
/// Should only be called in places that would otherwise clone this covspan.
fn refined_copy(&self) -> RefinedCovspan {
let &Self { span, bcb, is_closure } = self;
RefinedCovspan { span, bcb, is_closure }
}
fn into_refined(self) -> RefinedCovspan {
// Even though we consume self, we can just reuse the copying impl.
self.refined_copy()
}
}
#[derive(Debug)]
struct RefinedCovspan {
span: Span,
bcb: BasicCoverageBlock,
is_closure: bool,
}
impl RefinedCovspan {
fn is_mergeable(&self, other: &Self) -> bool {
self.bcb == other.bcb && !self.is_closure && !other.is_closure
}
fn merge_from(&mut self, other: &Self) {
debug_assert!(self.is_mergeable(other));
self.span = self.span.to(other.span);
}
}
/// Converts the initial set of coverage spans (one per MIR `Statement` or `Terminator`) into a
/// minimal set of coverage spans, using the BCB CFG to determine where it is safe and useful to:
/// ///
/// * Remove duplicate source code coverage regions /// * Remove duplicate source code coverage regions
/// * Merge spans that represent continuous (both in source code and control flow), non-branching /// * Merge spans that represent continuous (both in source code and control flow), non-branching
@ -145,43 +209,33 @@ struct SpansRefiner<'a> {
/// The BasicCoverageBlock Control Flow Graph (BCB CFG). /// The BasicCoverageBlock Control Flow Graph (BCB CFG).
basic_coverage_blocks: &'a CoverageGraph, basic_coverage_blocks: &'a CoverageGraph,
/// The initial set of `CoverageSpan`s, sorted by `Span` (`lo` and `hi`) and by relative /// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative
/// dominance between the `BasicCoverageBlock`s of equal `Span`s. /// dominance between the `BasicCoverageBlock`s of equal `Span`s.
sorted_spans_iter: std::vec::IntoIter<CoverageSpan>, sorted_spans_iter: std::vec::IntoIter<SpanFromMir>,
/// The current `CoverageSpan` to compare to its `prev`, to possibly merge, discard, force the /// The current coverage span to compare to its `prev`, to possibly merge, discard, force the
/// discard of the `prev` (and or `pending_dups`), or keep both (with `prev` moved to /// discard of the `prev` (and or `pending_dups`), or keep both (with `prev` moved to
/// `pending_dups`). If `curr` is not discarded or merged, it becomes `prev` for the next /// `pending_dups`). If `curr` is not discarded or merged, it becomes `prev` for the next
/// iteration. /// iteration.
some_curr: Option<CoverageSpan>, some_curr: Option<CurrCovspan>,
/// The original `span` for `curr`, in case `curr.span()` is modified. The `curr_original_span` /// The coverage span from a prior iteration; typically assigned from that iteration's `curr`.
/// **must not be mutated** (except when advancing to the next `curr`), even if `curr.span()`
/// is mutated.
curr_original_span: Span,
/// The CoverageSpan from a prior iteration; typically assigned from that iteration's `curr`.
/// If that `curr` was discarded, `prev` retains its value from the previous iteration. /// If that `curr` was discarded, `prev` retains its value from the previous iteration.
some_prev: Option<CoverageSpan>, some_prev: Option<PrevCovspan>,
/// Assigned from `curr_original_span` from the previous iteration. The `prev_original_span` /// One or more coverage spans with the same `Span` but different `BasicCoverageBlock`s, and
/// **must not be mutated** (except when advancing to the next `prev`), even if `prev.span()`
/// is mutated.
prev_original_span: Span,
/// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and
/// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list. /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list.
/// If a new `curr` span also fits this criteria (compared to an existing list of /// If a new `curr` span also fits this criteria (compared to an existing list of
/// `pending_dups`), that `curr` `CoverageSpan` moves to `prev` before possibly being added to /// `pending_dups`), that `curr` moves to `prev` before possibly being added to
/// the `pending_dups` list, on the next iteration. As a result, if `prev` and `pending_dups` /// the `pending_dups` list, on the next iteration. As a result, if `prev` and `pending_dups`
/// have the same `Span`, the criteria for `pending_dups` holds for `prev` as well: a `prev` /// have the same `Span`, the criteria for `pending_dups` holds for `prev` as well: a `prev`
/// with a matching `Span` does not dominate any `pending_dup` and no `pending_dup` dominates a /// with a matching `Span` does not dominate any `pending_dup` and no `pending_dup` dominates a
/// `prev` with a matching `Span`) /// `prev` with a matching `Span`)
pending_dups: Vec<CoverageSpan>, pending_dups: Vec<DuplicateCovspan>,
/// The final `CoverageSpan`s to add to the coverage map. A `Counter` or `Expression` /// The final coverage spans to add to the coverage map. A `Counter` or `Expression`
/// will also be injected into the MIR for each `CoverageSpan`. /// will also be injected into the MIR for each BCB that has associated spans.
refined_spans: Vec<CoverageSpan>, refined_spans: Vec<RefinedCovspan>,
} }
impl<'a> SpansRefiner<'a> { impl<'a> SpansRefiner<'a> {
@ -190,15 +244,13 @@ impl<'a> SpansRefiner<'a> {
/// and carving holes in spans when they overlap in unwanted ways. /// and carving holes in spans when they overlap in unwanted ways.
fn refine_sorted_spans( fn refine_sorted_spans(
basic_coverage_blocks: &'a CoverageGraph, basic_coverage_blocks: &'a CoverageGraph,
sorted_spans: Vec<CoverageSpan>, sorted_spans: Vec<SpanFromMir>,
) -> Vec<CoverageSpan> { ) -> Vec<RefinedCovspan> {
let this = Self { let this = Self {
basic_coverage_blocks, basic_coverage_blocks,
sorted_spans_iter: sorted_spans.into_iter(), sorted_spans_iter: sorted_spans.into_iter(),
some_curr: None, some_curr: None,
curr_original_span: DUMMY_SP,
some_prev: None, some_prev: None,
prev_original_span: DUMMY_SP,
pending_dups: Vec::new(), pending_dups: Vec::new(),
refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2), refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
}; };
@ -206,9 +258,9 @@ impl<'a> SpansRefiner<'a> {
this.to_refined_spans() this.to_refined_spans()
} }
/// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and /// Iterate through the sorted coverage spans, and return the refined list of merged and
/// de-duplicated `CoverageSpan`s. /// de-duplicated spans.
fn to_refined_spans(mut self) -> Vec<CoverageSpan> { fn to_refined_spans(mut self) -> Vec<RefinedCovspan> {
while self.next_coverage_span() { while self.next_coverage_span() {
// For the first span we don't have `prev` set, so most of the // For the first span we don't have `prev` set, so most of the
// span-processing steps don't make sense yet. // span-processing steps don't make sense yet.
@ -221,16 +273,15 @@ impl<'a> SpansRefiner<'a> {
let prev = self.prev(); let prev = self.prev();
let curr = self.curr(); let curr = self.curr();
if curr.is_mergeable(prev) { if prev.is_mergeable(curr) {
debug!(" same bcb (and neither is a closure), merge with prev={prev:?}"); debug!(" same bcb (and neither is a closure), merge with prev={prev:?}");
let prev = self.take_prev(); let curr = self.take_curr();
self.curr_mut().merge_from(&prev); self.prev_mut().merge_from(&curr);
// Note that curr.span may now differ from curr_original_span
} else if prev.span.hi() <= curr.span.lo() { } else if prev.span.hi() <= curr.span.lo() {
debug!( debug!(
" different bcbs and disjoint spans, so keep curr for next iter, and add prev={prev:?}", " different bcbs and disjoint spans, so keep curr for next iter, and add prev={prev:?}",
); );
let prev = self.take_prev(); let prev = self.take_prev().into_refined();
self.refined_spans.push(prev); self.refined_spans.push(prev);
} else if prev.is_closure { } else if prev.is_closure {
// drop any equal or overlapping span (`curr`) and keep `prev` to test again in the // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
@ -241,9 +292,9 @@ impl<'a> SpansRefiner<'a> {
self.take_curr(); // Discards curr. self.take_curr(); // Discards curr.
} else if curr.is_closure { } else if curr.is_closure {
self.carve_out_span_for_closure(); self.carve_out_span_for_closure();
} else if self.prev_original_span == curr.span { } else if prev.original_span == prev.span && prev.span == curr.span {
// `prev` and `curr` have the same span, or would have had the // Prev and curr have the same span, and prev's span hasn't
// same span before `prev` was modified by other spans. // been modified by other spans.
self.update_pending_dups(); self.update_pending_dups();
} else { } else {
self.cutoff_prev_at_overlapping_curr(); self.cutoff_prev_at_overlapping_curr();
@ -253,14 +304,14 @@ impl<'a> SpansRefiner<'a> {
// Drain any remaining dups into the output. // Drain any remaining dups into the output.
for dup in self.pending_dups.drain(..) { for dup in self.pending_dups.drain(..) {
debug!(" ...adding at least one pending dup={:?}", dup); debug!(" ...adding at least one pending dup={:?}", dup);
self.refined_spans.push(dup); self.refined_spans.push(dup.into_refined());
} }
// There is usually a final span remaining in `prev` after the loop ends, // There is usually a final span remaining in `prev` after the loop ends,
// so add it to the output as well. // so add it to the output as well.
if let Some(prev) = self.some_prev.take() { if let Some(prev) = self.some_prev.take() {
debug!(" AT END, adding last prev={prev:?}"); debug!(" AT END, adding last prev={prev:?}");
self.refined_spans.push(prev); self.refined_spans.push(prev.into_refined());
} }
// Do one last merge pass, to simplify the output. // Do one last merge pass, to simplify the output.
@ -274,7 +325,7 @@ impl<'a> SpansRefiner<'a> {
} }
}); });
// Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage // Remove spans derived from closures, originally added to ensure the coverage
// regions for the current function leave room for the closure's own coverage regions // regions for the current function leave room for the closure's own coverage regions
// (injected separately, from the closure's own MIR). // (injected separately, from the closure's own MIR).
self.refined_spans.retain(|covspan| !covspan.is_closure); self.refined_spans.retain(|covspan| !covspan.is_closure);
@ -282,34 +333,29 @@ impl<'a> SpansRefiner<'a> {
} }
#[track_caller] #[track_caller]
fn curr(&self) -> &CoverageSpan { fn curr(&self) -> &CurrCovspan {
self.some_curr.as_ref().unwrap_or_else(|| bug!("some_curr is None (curr)")) self.some_curr.as_ref().unwrap_or_else(|| bug!("some_curr is None (curr)"))
} }
#[track_caller]
fn curr_mut(&mut self) -> &mut CoverageSpan {
self.some_curr.as_mut().unwrap_or_else(|| bug!("some_curr is None (curr_mut)"))
}
/// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
/// `curr` coverage span. /// `curr` coverage span.
#[track_caller] #[track_caller]
fn take_curr(&mut self) -> CoverageSpan { fn take_curr(&mut self) -> CurrCovspan {
self.some_curr.take().unwrap_or_else(|| bug!("some_curr is None (take_curr)")) self.some_curr.take().unwrap_or_else(|| bug!("some_curr is None (take_curr)"))
} }
#[track_caller] #[track_caller]
fn prev(&self) -> &CoverageSpan { fn prev(&self) -> &PrevCovspan {
self.some_prev.as_ref().unwrap_or_else(|| bug!("some_prev is None (prev)")) self.some_prev.as_ref().unwrap_or_else(|| bug!("some_prev is None (prev)"))
} }
#[track_caller] #[track_caller]
fn prev_mut(&mut self) -> &mut CoverageSpan { fn prev_mut(&mut self) -> &mut PrevCovspan {
self.some_prev.as_mut().unwrap_or_else(|| bug!("some_prev is None (prev_mut)")) self.some_prev.as_mut().unwrap_or_else(|| bug!("some_prev is None (prev_mut)"))
} }
#[track_caller] #[track_caller]
fn take_prev(&mut self) -> CoverageSpan { fn take_prev(&mut self) -> PrevCovspan {
self.some_prev.take().unwrap_or_else(|| bug!("some_prev is None (take_prev)")) self.some_prev.take().unwrap_or_else(|| bug!("some_prev is None (take_prev)"))
} }
@ -335,7 +381,7 @@ impl<'a> SpansRefiner<'a> {
if last_dup.span.hi() <= self.curr().span.lo() { if last_dup.span.hi() <= self.curr().span.lo() {
for dup in self.pending_dups.drain(..) { for dup in self.pending_dups.drain(..) {
debug!(" ...adding at least one pending={:?}", dup); debug!(" ...adding at least one pending={:?}", dup);
self.refined_spans.push(dup); self.refined_spans.push(dup.into_refined());
} }
} else { } else {
self.pending_dups.clear(); self.pending_dups.clear();
@ -343,11 +389,10 @@ impl<'a> SpansRefiner<'a> {
assert!(self.pending_dups.is_empty()); assert!(self.pending_dups.is_empty());
} }
/// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order. /// Advance `prev` to `curr` (if any), and `curr` to the next coverage span in sorted order.
fn next_coverage_span(&mut self) -> bool { fn next_coverage_span(&mut self) -> bool {
if let Some(curr) = self.some_curr.take() { if let Some(curr) = self.some_curr.take() {
self.some_prev = Some(curr); self.some_prev = Some(curr.into_prev());
self.prev_original_span = self.curr_original_span;
} }
while let Some(curr) = self.sorted_spans_iter.next() { while let Some(curr) = self.sorted_spans_iter.next() {
debug!("FOR curr={:?}", curr); debug!("FOR curr={:?}", curr);
@ -362,10 +407,7 @@ impl<'a> SpansRefiner<'a> {
closure?); prev={prev:?}", closure?); prev={prev:?}",
); );
} else { } else {
// Save a copy of the original span for `curr` in case the `CoverageSpan` is changed self.some_curr = Some(CurrCovspan::new(curr.span, curr.bcb, curr.is_closure));
// by `self.curr_mut().merge_from(prev)`.
self.curr_original_span = curr.span;
self.some_curr.replace(curr);
self.maybe_flush_pending_dups(); self.maybe_flush_pending_dups();
return true; return true;
} }
@ -388,11 +430,11 @@ impl<'a> SpansRefiner<'a> {
let has_post_closure_span = prev.span.hi() > right_cutoff; let has_post_closure_span = prev.span.hi() > right_cutoff;
if has_pre_closure_span { if has_pre_closure_span {
let mut pre_closure = self.prev().clone(); let mut pre_closure = self.prev().refined_copy();
pre_closure.span = pre_closure.span.with_hi(left_cutoff); pre_closure.span = pre_closure.span.with_hi(left_cutoff);
debug!(" prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure); debug!(" prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure);
for mut dup in self.pending_dups.iter().cloned() { for mut dup in self.pending_dups.iter().map(DuplicateCovspan::refined_copy) {
dup.span = dup.span.with_hi(left_cutoff); dup.span = dup.span.with_hi(left_cutoff);
debug!(" ...and at least one pre_closure dup={:?}", dup); debug!(" ...and at least one pre_closure dup={:?}", dup);
self.refined_spans.push(dup); self.refined_spans.push(dup);
@ -402,9 +444,7 @@ impl<'a> SpansRefiner<'a> {
} }
if has_post_closure_span { if has_post_closure_span {
// Mutate `prev.span()` to start after the closure (and discard curr). // Mutate `prev.span` to start after the closure (and discard curr).
// (**NEVER** update `prev_original_span` because it affects the assumptions
// about how the `CoverageSpan`s are ordered.)
self.prev_mut().span = self.prev().span.with_lo(right_cutoff); self.prev_mut().span = self.prev().span.with_lo(right_cutoff);
debug!(" Mutated prev.span to start after the closure. prev={:?}", self.prev()); debug!(" Mutated prev.span to start after the closure. prev={:?}", self.prev());
@ -413,25 +453,26 @@ impl<'a> SpansRefiner<'a> {
dup.span = dup.span.with_lo(right_cutoff); dup.span = dup.span.with_lo(right_cutoff);
} }
let closure_covspan = self.take_curr(); // Prevent this curr from becoming prev. // Prevent this curr from becoming prev.
let closure_covspan = self.take_curr().into_refined();
self.refined_spans.push(closure_covspan); // since self.prev() was already updated self.refined_spans.push(closure_covspan); // since self.prev() was already updated
} else { } else {
self.pending_dups.clear(); self.pending_dups.clear();
} }
} }
/// Called if `curr.span` equals `prev_original_span` (and potentially equal to all /// Called if `curr.span` equals `prev.original_span` (and potentially equal to all
/// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed. /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed.
/// If prev.span() was merged into other spans (with matching BCB, for instance), /// If prev.span() was merged into other spans (with matching BCB, for instance),
/// `prev.span.hi()` will be greater than (further right of) `prev_original_span.hi()`. /// `prev.span.hi()` will be greater than (further right of) `prev.original_span.hi()`.
/// If prev.span() was split off to the right of a closure, prev.span().lo() will be /// If prev.span() was split off to the right of a closure, prev.span().lo() will be
/// greater than prev_original_span.lo(). The actual span of `prev_original_span` is /// greater than prev.original_span.lo(). The actual span of `prev.original_span` is
/// not as important as knowing that `prev()` **used to have the same span** as `curr()`, /// not as important as knowing that `prev()` **used to have the same span** as `curr()`,
/// which means their sort order is still meaningful for determining the dominator /// which means their sort order is still meaningful for determining the dominator
/// relationship. /// relationship.
/// ///
/// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if /// When two coverage spans have the same `Span`, dominated spans can be discarded; but if
/// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held, /// neither coverage span dominates the other, both (or possibly more than two) are held,
/// until their disposition is determined. In this latter case, the `prev` dup is moved into /// until their disposition is determined. In this latter case, the `prev` dup is moved into
/// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration. /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration.
fn update_pending_dups(&mut self) { fn update_pending_dups(&mut self) {
@ -439,9 +480,15 @@ impl<'a> SpansRefiner<'a> {
let curr_bcb = self.curr().bcb; let curr_bcb = self.curr().bcb;
// Equal coverage spans are ordered by dominators before dominated (if any), so it should be // Equal coverage spans are ordered by dominators before dominated (if any), so it should be
// impossible for `curr` to dominate any previous `CoverageSpan`. // impossible for `curr` to dominate any previous coverage span.
debug_assert!(!self.basic_coverage_blocks.dominates(curr_bcb, prev_bcb)); debug_assert!(!self.basic_coverage_blocks.dominates(curr_bcb, prev_bcb));
// `prev` is a duplicate of `curr`, so add it to the list of pending dups.
// If it dominates `curr`, it will be removed by the subsequent discard step.
let prev = self.take_prev().into_dup();
debug!(?prev, "adding prev to pending dups");
self.pending_dups.push(prev);
let initial_pending_count = self.pending_dups.len(); let initial_pending_count = self.pending_dups.len();
if initial_pending_count > 0 { if initial_pending_count > 0 {
self.pending_dups self.pending_dups
@ -454,42 +501,6 @@ impl<'a> SpansRefiner<'a> {
); );
} }
} }
if self.basic_coverage_blocks.dominates(prev_bcb, curr_bcb) {
debug!(
" different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}",
self.prev()
);
self.cutoff_prev_at_overlapping_curr();
// If one span dominates the other, associate the span with the code from the dominated
// block only (`curr`), and discard the overlapping portion of the `prev` span. (Note
// that if `prev.span` is wider than `prev_original_span`, a `CoverageSpan` will still
// be created for `prev`s block, for the non-overlapping portion, left of `curr.span`.)
//
// For example:
// match somenum {
// x if x < 1 => { ... }
// }...
//
// The span for the first `x` is referenced by both the pattern block (every time it is
// evaluated) and the arm code (only when matched). The counter will be applied only to
// the dominated block. This allows coverage to track and highlight things like the
// assignment of `x` above, if the branch is matched, making `x` available to the arm
// code; and to track and highlight the question mark `?` "try" operator at the end of
// a function call returning a `Result`, so the `?` is covered when the function returns
// an `Err`, and not counted as covered if the function always returns `Ok`.
} else {
// Save `prev` in `pending_dups`. (`curr` will become `prev` in the next iteration.)
// If the `curr` CoverageSpan is later discarded, `pending_dups` can be discarded as
// well; but if `curr` is added to refined_spans, the `pending_dups` will also be added.
debug!(
" different bcbs but SAME spans, and neither dominates, so keep curr for \
next iter, and, pending upcoming spans (unless overlapping) add prev={:?}",
self.prev()
);
let prev = self.take_prev();
self.pending_dups.push(prev);
}
} }
/// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_ /// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_
@ -512,7 +523,7 @@ impl<'a> SpansRefiner<'a> {
debug!(" ... no non-overlapping statements to add"); debug!(" ... no non-overlapping statements to add");
} else { } else {
debug!(" ... adding modified prev={:?}", self.prev()); debug!(" ... adding modified prev={:?}", self.prev());
let prev = self.take_prev(); let prev = self.take_prev().into_refined();
self.refined_spans.push(prev); self.refined_spans.push(prev);
} }
} else { } else {

View file

@ -9,7 +9,6 @@ use rustc_span::{ExpnKind, MacroKind, Span, Symbol};
use crate::coverage::graph::{ use crate::coverage::graph::{
BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB,
}; };
use crate::coverage::spans::CoverageSpan;
use crate::coverage::ExtractedHirInfo; use crate::coverage::ExtractedHirInfo;
/// Traverses the MIR body to produce an initial collection of coverage-relevant /// Traverses the MIR body to produce an initial collection of coverage-relevant
@ -22,7 +21,7 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
mir_body: &mir::Body<'_>, mir_body: &mir::Body<'_>,
hir_info: &ExtractedHirInfo, hir_info: &ExtractedHirInfo,
basic_coverage_blocks: &CoverageGraph, basic_coverage_blocks: &CoverageGraph,
) -> Vec<CoverageSpan> { ) -> Vec<SpanFromMir> {
let &ExtractedHirInfo { body_span, .. } = hir_info; let &ExtractedHirInfo { body_span, .. } = hir_info;
let mut initial_spans = vec![]; let mut initial_spans = vec![];
@ -61,7 +60,7 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
.then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse()) .then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse())
}); });
initial_spans.into_iter().map(SpanFromMir::into_coverage_span).collect::<Vec<_>>() initial_spans
} }
/// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate /// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate
@ -119,10 +118,10 @@ fn split_visible_macro_spans(initial_spans: &mut Vec<SpanFromMir>) {
initial_spans.extend(extra_spans); initial_spans.extend(extra_spans);
} }
// Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of // Generate a set of coverage spans from the filtered set of `Statement`s and `Terminator`s of
// the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One `CoverageSpan` is generated // the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One coverage span is generated
// for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will
// merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple // merge some coverage spans, at which point a coverage span may represent multiple
// `Statement`s and/or `Terminator`s.) // `Statement`s and/or `Terminator`s.)
fn bcb_to_initial_coverage_spans<'a, 'tcx>( fn bcb_to_initial_coverage_spans<'a, 'tcx>(
mir_body: &'a mir::Body<'tcx>, mir_body: &'a mir::Body<'tcx>,
@ -316,7 +315,7 @@ fn unexpand_into_body_span_with_prev(
} }
#[derive(Debug)] #[derive(Debug)]
struct SpanFromMir { pub(super) struct SpanFromMir {
/// A span that has been extracted from MIR and then "un-expanded" back to /// A span that has been extracted from MIR and then "un-expanded" back to
/// within the current function's `body_span`. After various intermediate /// within the current function's `body_span`. After various intermediate
/// processing steps, this span is emitted as part of the final coverage /// processing steps, this span is emitted as part of the final coverage
@ -324,10 +323,10 @@ struct SpanFromMir {
/// ///
/// With the exception of `fn_sig_span`, this should always be contained /// With the exception of `fn_sig_span`, this should always be contained
/// within `body_span`. /// within `body_span`.
span: Span, pub(super) span: Span,
visible_macro: Option<Symbol>, visible_macro: Option<Symbol>,
bcb: BasicCoverageBlock, pub(super) bcb: BasicCoverageBlock,
is_closure: bool, pub(super) is_closure: bool,
} }
impl SpanFromMir { impl SpanFromMir {
@ -343,9 +342,4 @@ impl SpanFromMir {
) -> Self { ) -> Self {
Self { span, visible_macro, bcb, is_closure } Self { span, visible_macro, bcb, is_closure }
} }
fn into_coverage_span(self) -> CoverageSpan {
let Self { span, visible_macro: _, bcb, is_closure } = self;
CoverageSpan::new(span, bcb, is_closure)
}
} }

View file

@ -322,10 +322,9 @@ impl Session {
} }
} }
/// Used for code paths of expensive computations that should only take place when /// Record the fact that we called `trimmed_def_paths`, and do some
/// warnings or errors are emitted. If no messages are emitted ("good path"), then /// checking about whether its cost was justified.
/// it's likely a bug. pub fn record_trimmed_def_paths(&self) {
pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
if self.opts.unstable_opts.print_type_sizes if self.opts.unstable_opts.print_type_sizes
|| self.opts.unstable_opts.query_dep_graph || self.opts.unstable_opts.query_dep_graph
|| self.opts.unstable_opts.dump_mir.is_some() || self.opts.unstable_opts.dump_mir.is_some()
@ -336,7 +335,7 @@ impl Session {
return; return;
} }
self.dcx().good_path_delayed_bug(msg) self.dcx().set_must_produce_diag()
} }
#[inline] #[inline]
@ -546,8 +545,8 @@ impl Session {
if fuel.remaining == 0 && !fuel.out_of_fuel { if fuel.remaining == 0 && !fuel.out_of_fuel {
if self.dcx().can_emit_warnings() { if self.dcx().can_emit_warnings() {
// We only call `msg` in case we can actually emit warnings. // We only call `msg` in case we can actually emit warnings.
// Otherwise, this could cause a `good_path_delayed_bug` to // Otherwise, this could cause a `must_produce_diag` ICE
// trigger (issue #79546). // (issue #79546).
self.dcx().emit_warn(errors::OptimisationFuelExhausted { msg: msg() }); self.dcx().emit_warn(errors::OptimisationFuelExhausted { msg: msg() });
} }
fuel.out_of_fuel = true; fuel.out_of_fuel = true;

View file

@ -3,33 +3,27 @@
//! of our more general approach to "lazy normalization". //! of our more general approach to "lazy normalization".
//! //!
//! This is done by first normalizing both sides of the goal, ending up in //! This is done by first normalizing both sides of the goal, ending up in
//! either a concrete type, rigid projection, opaque, or an infer variable. //! either a concrete type, rigid alias, or an infer variable.
//! These are related further according to the rules below: //! These are related further according to the rules below:
//! //!
//! (1.) If we end up with a rigid projection and a rigid projection, then we //! (1.) If we end up with two rigid aliases, then we relate them structurally.
//! relate those projections structurally.
//! //!
//! (2.) If we end up with a rigid projection and an alias, then the opaque will //! (2.) If we end up with an infer var and a rigid alias, then
//! have its hidden type defined to be that rigid projection.
//!
//! (3.) If we end up with an opaque and an opaque, then we assemble two
//! candidates, one defining the LHS to be the hidden type of the RHS, and vice
//! versa.
//!
//! (4.) If we end up with an infer var and an opaque or rigid projection, then
//! we assign the alias to the infer var. //! we assign the alias to the infer var.
//! //!
//! (5.) If we end up with an opaque and a rigid (non-projection) type, then we //! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
//! define the hidden type of the opaque to be the rigid type.
//!
//! (6.) Otherwise, if we end with two rigid (non-projection) or infer types,
//! relate them structurally. //! relate them structurally.
//!
//! Subtle: when relating an opaque to another type, we emit a
//! `NormalizesTo(opaque, ?fresh_var)` goal when trying to normalize the opaque.
//! This nested goal starts out as ambiguous and does not actually define the opaque.
//! However, if `?fresh_var` ends up geteting equated to another type, we retry the
//! `NormalizesTo` goal, at which point the opaque is actually defined.
use super::{EvalCtxt, GoalSource}; use super::{EvalCtxt, GoalSource};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty; use rustc_middle::ty::{self, Ty};
impl<'tcx> EvalCtxt<'_, 'tcx> { impl<'tcx> EvalCtxt<'_, 'tcx> {
#[instrument(level = "debug", skip(self), ret)] #[instrument(level = "debug", skip(self), ret)]
@ -59,37 +53,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} }
(Some(alias), None) => { (Some(_), None) => {
if rhs.is_infer() { if rhs.is_infer() {
self.relate(param_env, lhs, variance, rhs)?; self.relate(param_env, lhs, variance, rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else if alias.is_opaque(tcx) {
// FIXME: This doesn't account for variance.
self.define_opaque(param_env, alias, rhs)
} else { } else {
Err(NoSolution) Err(NoSolution)
} }
} }
(None, Some(alias)) => { (None, Some(_)) => {
if lhs.is_infer() { if lhs.is_infer() {
self.relate(param_env, lhs, variance, rhs)?; self.relate(param_env, lhs, variance, rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else if alias.is_opaque(tcx) {
// FIXME: This doesn't account for variance.
self.define_opaque(param_env, alias, lhs)
} else { } else {
Err(NoSolution) Err(NoSolution)
} }
} }
(Some(alias_lhs), Some(alias_rhs)) => { (Some(alias_lhs), Some(alias_rhs)) => {
self.relate_rigid_alias_or_opaque(param_env, alias_lhs, variance, alias_rhs) self.relate(param_env, alias_lhs, variance, alias_rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} }
} }
} }
// FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var. // FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var.
/// Normalize the `term` to equate it later. This does not define opaque types. /// Normalize the `term` to equate it later.
#[instrument(level = "debug", skip(self, param_env), ret)] #[instrument(level = "debug", skip(self, param_env), ret)]
fn try_normalize_term( fn try_normalize_term(
&mut self, &mut self,
@ -98,10 +87,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
) -> Result<Option<ty::Term<'tcx>>, NoSolution> { ) -> Result<Option<ty::Term<'tcx>>, NoSolution> {
match term.unpack() { match term.unpack() {
ty::TermKind::Ty(ty) => { ty::TermKind::Ty(ty) => {
// We do no define opaque types here but instead do so in `relate_rigid_alias_or_opaque`. Ok(self.try_normalize_ty_recur(param_env, 0, ty).map(Into::into))
Ok(self
.try_normalize_ty_recur(param_env, DefineOpaqueTypes::No, 0, ty)
.map(Into::into))
} }
ty::TermKind::Const(_) => { ty::TermKind::Const(_) => {
if let Some(alias) = term.to_alias_ty(self.tcx()) { if let Some(alias) = term.to_alias_ty(self.tcx()) {
@ -119,51 +105,34 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
} }
} }
fn define_opaque( fn try_normalize_ty_recur(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
opaque: ty::AliasTy<'tcx>, depth: usize,
term: ty::Term<'tcx>, ty: Ty<'tcx>,
) -> QueryResult<'tcx> { ) -> Option<Ty<'tcx>> {
self.add_goal( if !self.tcx().recursion_limit().value_within_limit(depth) {
GoalSource::Misc, return None;
Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }),
);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
fn relate_rigid_alias_or_opaque(
&mut self,
param_env: ty::ParamEnv<'tcx>,
lhs: ty::AliasTy<'tcx>,
variance: ty::Variance,
rhs: ty::AliasTy<'tcx>,
) -> QueryResult<'tcx> {
let tcx = self.tcx();
let mut candidates = vec![];
if lhs.is_opaque(tcx) {
candidates.extend(
self.probe_misc_candidate("define-lhs-opaque")
.enter(|ecx| ecx.define_opaque(param_env, lhs, rhs.to_ty(tcx).into())),
);
} }
if rhs.is_opaque(tcx) { let ty::Alias(_, alias) = *ty.kind() else {
candidates.extend( return Some(ty);
self.probe_misc_candidate("define-rhs-opaque") };
.enter(|ecx| ecx.define_opaque(param_env, rhs, lhs.to_ty(tcx).into())),
match self.commit_if_ok(|this| {
let normalized_ty = this.next_ty_infer();
let normalizes_to_goal = Goal::new(
this.tcx(),
param_env,
ty::NormalizesTo { alias, term: normalized_ty.into() },
); );
} this.add_goal(GoalSource::Misc, normalizes_to_goal);
this.try_evaluate_added_goals()?;
candidates.extend(self.probe_misc_candidate("args-relate").enter(|ecx| { let ty = this.resolve_vars_if_possible(normalized_ty);
ecx.relate(param_env, lhs, variance, rhs)?; Ok(this.try_normalize_ty_recur(param_env, depth + 1, ty))
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) {
})); Ok(ty) => ty,
Err(NoSolution) => Some(ty),
if let Some(result) = self.try_merge_responses(&candidates) {
Ok(result)
} else {
self.flounder(&candidates)
} }
} }
} }

View file

@ -276,11 +276,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
&mut self, &mut self,
goal: Goal<'tcx, G>, goal: Goal<'tcx, G>,
) -> Vec<Candidate<'tcx>> { ) -> Vec<Candidate<'tcx>> {
let Some(normalized_self_ty) = let Ok(normalized_self_ty) =
self.try_normalize_ty(goal.param_env, goal.predicate.self_ty()) self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
else { else {
debug!("overflow while evaluating self type"); return vec![];
return self.forced_ambiguity(MaybeCause::Overflow);
}; };
if normalized_self_ty.is_ty_var() { if normalized_self_ty.is_ty_var() {
@ -635,19 +634,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
return; return;
} }
match self.try_normalize_ty(goal.param_env, alias_ty.self_ty()) { // Recurse on the self type of the projection.
// Recurse on the self type of the projection. match self.structurally_normalize_ty(goal.param_env, alias_ty.self_ty()) {
Some(next_self_ty) => { Ok(next_self_ty) => {
self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates); self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates)
}
// Bail if we overflow when normalizing, adding an ambiguous candidate.
None => {
if let Ok(result) =
self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW)
{
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
}
} }
Err(NoSolution) => {}
} }
} }
@ -857,19 +849,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let tcx = self.tcx(); let tcx = self.tcx();
let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| { let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| {
let trait_ref = goal.predicate.trait_ref(tcx); let trait_ref = goal.predicate.trait_ref(tcx);
#[derive(Debug)] let lazily_normalize_ty = |ty| ecx.structurally_normalize_ty(goal.param_env, ty);
struct Overflow;
let lazily_normalize_ty = |ty| match ecx.try_normalize_ty(goal.param_env, ty) {
Some(ty) => Ok(ty),
None => Err(Overflow),
};
match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty) { match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty)? {
Err(Overflow) => { Ok(()) => Err(NoSolution),
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW) Err(_) => {
}
Ok(Ok(())) => Err(NoSolution),
Ok(Err(_)) => {
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
} }
} }

View file

@ -15,15 +15,13 @@
//! about it on zulip. //! about it on zulip.
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::infer::canonical::CanonicalVarInfos;
use rustc_middle::traits::solve::{ use rustc_middle::traits::solve::{
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack, CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
QueryResult, Response, QueryResult, Response,
}; };
use rustc_middle::traits::Reveal; use rustc_middle::ty::{self, AliasRelationDirection, Ty, TyCtxt, UniverseIndex};
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
use rustc_middle::ty::{ use rustc_middle::ty::{
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate, CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
}; };
@ -267,71 +265,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
Ok(self.make_ambiguous_response_no_constraints(maybe_cause)) Ok(self.make_ambiguous_response_no_constraints(maybe_cause))
} }
/// Normalize a type when it is structually matched on. /// Normalize a type for when it is structurally matched on.
/// ///
/// In nearly all cases this function must be used before matching on a type. /// This function is necessary in nearly all cases before matching on a type.
/// Not doing so is likely to be incomplete and therefore unsound during /// Not doing so is likely to be incomplete and therefore unsound during
/// coherence. /// coherence.
#[instrument(level = "debug", skip(self), ret)] fn structurally_normalize_ty(
fn try_normalize_ty(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> Option<Ty<'tcx>> { ) -> Result<Ty<'tcx>, NoSolution> {
self.try_normalize_ty_recur(param_env, DefineOpaqueTypes::Yes, 0, ty) if let ty::Alias(..) = ty.kind() {
} let normalized_ty = self.next_ty_infer();
let alias_relate_goal = Goal::new(
fn try_normalize_ty_recur( self.tcx(),
&mut self,
param_env: ty::ParamEnv<'tcx>,
define_opaque_types: DefineOpaqueTypes,
depth: usize,
ty: Ty<'tcx>,
) -> Option<Ty<'tcx>> {
if !self.tcx().recursion_limit().value_within_limit(depth) {
return None;
}
let ty::Alias(kind, alias) = *ty.kind() else {
return Some(ty);
};
// We do no always define opaque types eagerly to allow non-defining uses
// in the defining scope. However, if we can unify this opaque to an existing
// opaque, then we should attempt to eagerly reveal the opaque, and we fall
// through.
if let DefineOpaqueTypes::No = define_opaque_types
&& let Reveal::UserFacing = param_env.reveal()
&& let ty::Opaque = kind
&& let Some(def_id) = alias.def_id.as_local()
&& self.can_define_opaque_ty(def_id)
{
if self
.unify_existing_opaque_tys(
param_env,
OpaqueTypeKey { def_id, args: alias.args },
self.next_ty_infer(),
)
.is_empty()
{
return Some(ty);
}
}
match self.commit_if_ok(|this| {
let normalized_ty = this.next_ty_infer();
let normalizes_to_goal = Goal::new(
this.tcx(),
param_env, param_env,
ty::NormalizesTo { alias, term: normalized_ty.into() }, ty::PredicateKind::AliasRelate(
ty.into(),
normalized_ty.into(),
AliasRelationDirection::Equate,
),
); );
this.add_goal(GoalSource::Misc, normalizes_to_goal); self.add_goal(GoalSource::Misc, alias_relate_goal);
this.try_evaluate_added_goals()?; self.try_evaluate_added_goals()?;
let ty = this.resolve_vars_if_possible(normalized_ty); Ok(self.resolve_vars_if_possible(normalized_ty))
Ok(this.try_normalize_ty_recur(param_env, define_opaque_types, depth + 1, ty)) } else {
}) { Ok(ty)
Ok(ty) => ty,
Err(NoSolution) => Some(ty),
} }
} }
} }

View file

@ -58,21 +58,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
} }
} }
let expected = match self.try_normalize_ty(goal.param_env, expected) { let expected = self.structurally_normalize_ty(goal.param_env, expected)?;
Some(ty) => { if expected.is_ty_var() {
if ty.is_ty_var() { return self
return self.evaluate_added_goals_and_make_canonical_response( .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
Certainty::AMBIGUOUS, }
);
} else {
ty
}
}
None => {
return self
.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
}
};
// Otherwise, define a new opaque type // Otherwise, define a new opaque type
self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;

View file

@ -584,11 +584,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
let a_ty = goal.predicate.self_ty(); let a_ty = goal.predicate.self_ty();
// We need to normalize the b_ty since it's matched structurally // We need to normalize the b_ty since it's matched structurally
// in the other functions below. // in the other functions below.
let b_ty = match ecx let Ok(b_ty) = ecx.structurally_normalize_ty(
.try_normalize_ty(goal.param_env, goal.predicate.trait_ref.args.type_at(1)) goal.param_env,
{ goal.predicate.trait_ref.args.type_at(1),
Some(b_ty) => b_ty, ) else {
None => return vec![misc_candidate(ecx, Certainty::OVERFLOW)], return vec![];
}; };
let goal = goal.with(ecx.tcx(), (a_ty, b_ty)); let goal = goal.with(ecx.tcx(), (a_ty, b_ty));

View file

@ -151,3 +151,21 @@ will be given, even if the link fails to resolve. For example, any link containi
characters will be ignored. characters will be ignored.
[#72243]: https://github.com/rust-lang/rust/issues/72243 [#72243]: https://github.com/rust-lang/rust/issues/72243
## What happens in case an intra-doc link cannot be generated
In some cases (items behind a `cfg` for example), an intra-doc link cannot be generated to item.
There are different ways to create a link in markdown, and depending on the one you use, it will
render differently in this case:
```md
1. [a]
2. [b][c]
3. [d](e)
4. [f]
[f]: g
```
`1.` and `2.` will will be displayed as is in the rendered documentation (ie, `[a]` and `[b][c]`)
whereas `3.` and `4.` will be replaced by a link targetting `e` for `[d](e)` and `g` for `[f]`.

View file

@ -170,3 +170,32 @@ There are a few attributes which are not inlined though:
All other attributes are inherited when inlined, so that the documentation matches the behavior if All other attributes are inherited when inlined, so that the documentation matches the behavior if
the inlined item was directly defined at the spot where it's shown. the inlined item was directly defined at the spot where it's shown.
These rules also apply if the item is inlined with a glob re-export:
```rust,ignore (inline)
mod private_mod {
/// First
#[cfg(a)]
pub struct InPrivate;
}
#[cfg(c)]
pub use self::private_mod::*;
```
Otherwise, the attributes displayed will be from the re-exported item and the attributes on the
re-export itself will be ignored:
```rust,ignore (inline)
mod private_mod {
/// First
#[cfg(a)]
pub struct InPrivate;
}
#[cfg(c)]
pub use self::private_mod::InPrivate;
```
In the above case, `cfg(c)` will not be displayed in the docs.

View file

@ -4,3 +4,4 @@ author = "The Rust Community"
[output.html] [output.html]
git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/unstable-book" git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/unstable-book"
edit-url-template = "https://github.com/rust-lang/rust/edit/master/src/doc/unstable-book/{path}"

View file

@ -2736,7 +2736,7 @@ fn add_without_unwanted_attributes<'hir>(
if ident == sym::doc { if ident == sym::doc {
filter_doc_attr(normal, is_inline); filter_doc_attr(normal, is_inline);
attrs.push((Cow::Owned(attr), import_parent)); attrs.push((Cow::Owned(attr), import_parent));
} else if ident != sym::cfg { } else if is_inline || ident != sym::cfg {
// If it's not a `cfg()` attribute, we keep it. // If it's not a `cfg()` attribute, we keep it.
attrs.push((Cow::Owned(attr), import_parent)); attrs.push((Cow::Owned(attr), import_parent));
} }

View file

@ -110,7 +110,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>,
bb0: { bb0: {
_39 = discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2}))); _39 = discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})));
switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb9]; switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb8];
} }
bb1: { bb1: {
@ -165,10 +165,14 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>,
StorageDead(_10); StorageDead(_10);
PlaceMention(_9); PlaceMention(_9);
_16 = discriminant(_9); _16 = discriminant(_9);
switchInt(move _16) -> [0: bb10, 1: bb8, otherwise: bb9]; switchInt(move _16) -> [0: bb10, 1: bb9, otherwise: bb8];
} }
bb8: { bb8: {
unreachable;
}
bb9: {
_8 = const (); _8 = const ();
StorageDead(_14); StorageDead(_14);
StorageDead(_12); StorageDead(_12);
@ -186,10 +190,6 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>,
return; return;
} }
bb9: {
unreachable;
}
bb10: { bb10: {
StorageLive(_17); StorageLive(_17);
_17 = ((_9 as Ready).0: ()); _17 = ((_9 as Ready).0: ());
@ -267,7 +267,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>,
StorageDead(_26); StorageDead(_26);
PlaceMention(_25); PlaceMention(_25);
_32 = discriminant(_25); _32 = discriminant(_25);
switchInt(move _32) -> [0: bb21, 1: bb20, otherwise: bb9]; switchInt(move _32) -> [0: bb21, 1: bb20, otherwise: bb8];
} }
bb20: { bb20: {

View file

@ -27,13 +27,13 @@ fn main() -> () {
StorageLive(_5); StorageLive(_5);
PlaceMention(_1); PlaceMention(_1);
_6 = discriminant(_1); _6 = discriminant(_1);
switchInt(move _6) -> [1: bb4, otherwise: bb3]; switchInt(move _6) -> [1: bb5, otherwise: bb4];
} }
bb1: { bb1: {
StorageLive(_3); StorageLive(_3);
StorageLive(_4); StorageLive(_4);
_4 = begin_panic::<&str>(const "explicit panic") -> bb7; _4 = begin_panic::<&str>(const "explicit panic") -> bb8;
} }
bb2: { bb2: {
@ -43,14 +43,19 @@ fn main() -> () {
} }
bb3: { bb3: {
goto -> bb6; FakeRead(ForMatchedPlace(None), _1);
unreachable;
} }
bb4: { bb4: {
falseEdge -> [real: bb5, imaginary: bb3]; goto -> bb7;
} }
bb5: { bb5: {
falseEdge -> [real: bb6, imaginary: bb4];
}
bb6: {
_5 = ((_1 as Some).0: u8); _5 = ((_1 as Some).0: u8);
_0 = const (); _0 = const ();
StorageDead(_5); StorageDead(_5);
@ -58,12 +63,12 @@ fn main() -> () {
return; return;
} }
bb6: { bb7: {
StorageDead(_5); StorageDead(_5);
goto -> bb1; goto -> bb1;
} }
bb7 (cleanup): { bb8 (cleanup): {
resume; resume;
} }
} }

View file

@ -17,7 +17,7 @@ fn main() -> () {
} }
bb1: { bb1: {
falseUnwind -> [real: bb2, unwind: bb11]; falseUnwind -> [real: bb2, unwind: bb12];
} }
bb2: { bb2: {
@ -25,41 +25,46 @@ fn main() -> () {
StorageLive(_3); StorageLive(_3);
_3 = const true; _3 = const true;
PlaceMention(_3); PlaceMention(_3);
switchInt(_3) -> [0: bb3, otherwise: bb4]; switchInt(_3) -> [0: bb4, otherwise: bb5];
} }
bb3: { bb3: {
falseEdge -> [real: bb5, imaginary: bb4]; FakeRead(ForMatchedPlace(None), _3);
}
bb4: {
_0 = const ();
goto -> bb10;
}
bb5: {
_2 = const 4_i32;
goto -> bb8;
}
bb6: {
unreachable; unreachable;
} }
bb4: {
falseEdge -> [real: bb6, imaginary: bb5];
}
bb5: {
_0 = const ();
goto -> bb11;
}
bb6: {
_2 = const 4_i32;
goto -> bb9;
}
bb7: { bb7: {
goto -> bb8; unreachable;
} }
bb8: { bb8: {
goto -> bb9;
}
bb9: {
FakeRead(ForLet(None), _2); FakeRead(ForLet(None), _2);
StorageDead(_3); StorageDead(_3);
StorageLive(_5); StorageLive(_5);
StorageLive(_6); StorageLive(_6);
_6 = &_2; _6 = &_2;
_5 = std::mem::drop::<&i32>(move _6) -> [return: bb9, unwind: bb11]; _5 = std::mem::drop::<&i32>(move _6) -> [return: bb10, unwind: bb12];
} }
bb9: { bb10: {
StorageDead(_6); StorageDead(_6);
StorageDead(_5); StorageDead(_5);
_1 = const (); _1 = const ();
@ -67,13 +72,13 @@ fn main() -> () {
goto -> bb1; goto -> bb1;
} }
bb10: { bb11: {
StorageDead(_3); StorageDead(_3);
StorageDead(_2); StorageDead(_2);
return; return;
} }
bb11 (cleanup): { bb12 (cleanup): {
resume; resume;
} }
} }

View file

@ -19,168 +19,178 @@ fn test_complex() -> () {
bb0: { bb0: {
StorageLive(_1); StorageLive(_1);
StorageLive(_2); StorageLive(_2);
_2 = E::f() -> [return: bb1, unwind: bb31]; _2 = E::f() -> [return: bb1, unwind: bb33];
} }
bb1: { bb1: {
PlaceMention(_2); PlaceMention(_2);
_3 = discriminant(_2); _3 = discriminant(_2);
switchInt(move _3) -> [0: bb2, otherwise: bb3]; switchInt(move _3) -> [0: bb4, otherwise: bb3];
} }
bb2: { bb2: {
falseEdge -> [real: bb4, imaginary: bb3]; FakeRead(ForMatchedPlace(None), _2);
unreachable;
} }
bb3: { bb3: {
goto -> bb19; goto -> bb20;
} }
bb4: { bb4: {
StorageLive(_4); falseEdge -> [real: bb5, imaginary: bb3];
_4 = always_true() -> [return: bb5, unwind: bb31];
} }
bb5: { bb5: {
switchInt(move _4) -> [0: bb7, otherwise: bb6]; StorageLive(_4);
_4 = always_true() -> [return: bb6, unwind: bb33];
} }
bb6: { bb6: {
switchInt(move _4) -> [0: bb8, otherwise: bb7];
}
bb7: {
StorageLive(_5); StorageLive(_5);
StorageLive(_6); StorageLive(_6);
StorageLive(_7); StorageLive(_7);
_7 = Droppy(const 0_u8); _7 = Droppy(const 0_u8);
_6 = (_7.0: u8); _6 = (_7.0: u8);
_5 = Gt(move _6, const 0_u8); _5 = Gt(move _6, const 0_u8);
switchInt(move _5) -> [0: bb9, otherwise: bb8]; switchInt(move _5) -> [0: bb10, otherwise: bb9];
}
bb7: {
goto -> bb13;
} }
bb8: { bb8: {
drop(_7) -> [return: bb10, unwind: bb31]; goto -> bb14;
} }
bb9: { bb9: {
goto -> bb11; drop(_7) -> [return: bb11, unwind: bb33];
} }
bb10: { bb10: {
StorageDead(_7); goto -> bb12;
StorageDead(_6);
goto -> bb16;
} }
bb11: { bb11: {
drop(_7) -> [return: bb12, unwind: bb31]; StorageDead(_7);
StorageDead(_6);
goto -> bb17;
} }
bb12: { bb12: {
StorageDead(_7); drop(_7) -> [return: bb13, unwind: bb33];
StorageDead(_6);
goto -> bb13;
} }
bb13: { bb13: {
StorageDead(_7);
StorageDead(_6);
goto -> bb14;
}
bb14: {
StorageLive(_8); StorageLive(_8);
StorageLive(_9); StorageLive(_9);
StorageLive(_10); StorageLive(_10);
_10 = Droppy(const 1_u8); _10 = Droppy(const 1_u8);
_9 = (_10.0: u8); _9 = (_10.0: u8);
_8 = Gt(move _9, const 1_u8); _8 = Gt(move _9, const 1_u8);
switchInt(move _8) -> [0: bb15, otherwise: bb14]; switchInt(move _8) -> [0: bb16, otherwise: bb15];
}
bb14: {
drop(_10) -> [return: bb16, unwind: bb31];
} }
bb15: { bb15: {
goto -> bb17; drop(_10) -> [return: bb17, unwind: bb33];
} }
bb16: { bb16: {
StorageDead(_10); goto -> bb18;
StorageDead(_9);
_1 = const ();
goto -> bb20;
} }
bb17: { bb17: {
drop(_10) -> [return: bb18, unwind: bb31]; StorageDead(_10);
StorageDead(_9);
_1 = const ();
goto -> bb21;
} }
bb18: { bb18: {
StorageDead(_10); drop(_10) -> [return: bb19, unwind: bb33];
StorageDead(_9);
goto -> bb19;
} }
bb19: { bb19: {
_1 = const (); StorageDead(_10);
StorageDead(_9);
goto -> bb20; goto -> bb20;
} }
bb20: { bb20: {
_1 = const ();
goto -> bb21;
}
bb21: {
StorageDead(_8); StorageDead(_8);
StorageDead(_5); StorageDead(_5);
StorageDead(_4); StorageDead(_4);
StorageDead(_2); StorageDead(_2);
StorageDead(_1); StorageDead(_1);
StorageLive(_11); StorageLive(_11);
_11 = always_true() -> [return: bb21, unwind: bb31]; _11 = always_true() -> [return: bb22, unwind: bb33];
}
bb21: {
switchInt(move _11) -> [0: bb23, otherwise: bb22];
} }
bb22: { bb22: {
goto -> bb29; switchInt(move _11) -> [0: bb24, otherwise: bb23];
} }
bb23: { bb23: {
goto -> bb24; goto -> bb31;
} }
bb24: { bb24: {
StorageLive(_12); goto -> bb25;
_12 = E::f() -> [return: bb25, unwind: bb31];
} }
bb25: { bb25: {
PlaceMention(_12); StorageLive(_12);
_13 = discriminant(_12); _12 = E::f() -> [return: bb26, unwind: bb33];
switchInt(move _13) -> [1: bb27, otherwise: bb26];
} }
bb26: { bb26: {
goto -> bb29; PlaceMention(_12);
_13 = discriminant(_12);
switchInt(move _13) -> [1: bb29, otherwise: bb28];
} }
bb27: { bb27: {
falseEdge -> [real: bb28, imaginary: bb26]; FakeRead(ForMatchedPlace(None), _12);
unreachable;
} }
bb28: { bb28: {
_0 = const (); goto -> bb31;
goto -> bb30;
} }
bb29: { bb29: {
_0 = const (); falseEdge -> [real: bb30, imaginary: bb28];
goto -> bb30;
} }
bb30: { bb30: {
_0 = const ();
goto -> bb32;
}
bb31: {
_0 = const ();
goto -> bb32;
}
bb32: {
StorageDead(_11); StorageDead(_11);
StorageDead(_12); StorageDead(_12);
return; return;
} }
bb31 (cleanup): { bb33 (cleanup): {
resume; resume;
} }
} }

View file

@ -28,25 +28,25 @@ fn full_tested_match() -> () {
_2 = Option::<i32>::Some(const 42_i32); _2 = Option::<i32>::Some(const 42_i32);
PlaceMention(_2); PlaceMention(_2);
_3 = discriminant(_2); _3 = discriminant(_2);
switchInt(move _3) -> [0: bb1, 1: bb2, otherwise: bb4]; switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
} }
bb1: { bb1: {
FakeRead(ForMatchedPlace(None), _2);
unreachable;
}
bb2: {
_1 = (const 3_i32, const 3_i32); _1 = (const 3_i32, const 3_i32);
goto -> bb11; goto -> bb11;
} }
bb2: {
falseEdge -> [real: bb5, imaginary: bb3];
}
bb3: { bb3: {
falseEdge -> [real: bb10, imaginary: bb1]; falseEdge -> [real: bb5, imaginary: bb4];
} }
bb4: { bb4: {
FakeRead(ForMatchedPlace(None), _2); falseEdge -> [real: bb10, imaginary: bb2];
unreachable;
} }
bb5: { bb5: {
@ -54,7 +54,7 @@ fn full_tested_match() -> () {
_6 = &((_2 as Some).0: i32); _6 = &((_2 as Some).0: i32);
_4 = &fake _2; _4 = &fake _2;
StorageLive(_7); StorageLive(_7);
_7 = guard() -> [return: bb6, unwind: bb12]; _7 = guard() -> [return: bb6, unwind: bb13];
} }
bb6: { bb6: {
@ -83,7 +83,7 @@ fn full_tested_match() -> () {
bb9: { bb9: {
StorageDead(_7); StorageDead(_7);
StorageDead(_6); StorageDead(_6);
goto -> bb3; goto -> bb4;
} }
bb10: { bb10: {
@ -105,7 +105,12 @@ fn full_tested_match() -> () {
return; return;
} }
bb12 (cleanup): { bb12: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
bb13 (cleanup): {
resume; resume;
} }
} }

View file

@ -28,18 +28,23 @@ fn full_tested_match2() -> () {
_2 = Option::<i32>::Some(const 42_i32); _2 = Option::<i32>::Some(const 42_i32);
PlaceMention(_2); PlaceMention(_2);
_3 = discriminant(_2); _3 = discriminant(_2);
switchInt(move _3) -> [0: bb1, 1: bb2, otherwise: bb4]; switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
} }
bb1: { bb1: {
falseEdge -> [real: bb10, imaginary: bb3]; FakeRead(ForMatchedPlace(None), _2);
unreachable;
} }
bb2: { bb2: {
falseEdge -> [real: bb5, imaginary: bb1]; falseEdge -> [real: bb10, imaginary: bb4];
} }
bb3: { bb3: {
falseEdge -> [real: bb5, imaginary: bb2];
}
bb4: {
StorageLive(_9); StorageLive(_9);
_9 = ((_2 as Some).0: i32); _9 = ((_2 as Some).0: i32);
StorageLive(_10); StorageLive(_10);
@ -50,17 +55,12 @@ fn full_tested_match2() -> () {
goto -> bb11; goto -> bb11;
} }
bb4: {
FakeRead(ForMatchedPlace(None), _2);
unreachable;
}
bb5: { bb5: {
StorageLive(_6); StorageLive(_6);
_6 = &((_2 as Some).0: i32); _6 = &((_2 as Some).0: i32);
_4 = &fake _2; _4 = &fake _2;
StorageLive(_7); StorageLive(_7);
_7 = guard() -> [return: bb6, unwind: bb12]; _7 = guard() -> [return: bb6, unwind: bb13];
} }
bb6: { bb6: {
@ -89,7 +89,7 @@ fn full_tested_match2() -> () {
bb9: { bb9: {
StorageDead(_7); StorageDead(_7);
StorageDead(_6); StorageDead(_6);
falseEdge -> [real: bb3, imaginary: bb1]; falseEdge -> [real: bb4, imaginary: bb2];
} }
bb10: { bb10: {
@ -105,7 +105,12 @@ fn full_tested_match2() -> () {
return; return;
} }
bb12 (cleanup): { bb12: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
bb13 (cleanup): {
resume; resume;
} }
} }

View file

@ -39,55 +39,60 @@ fn main() -> () {
_2 = Option::<i32>::Some(const 1_i32); _2 = Option::<i32>::Some(const 1_i32);
PlaceMention(_2); PlaceMention(_2);
_4 = discriminant(_2); _4 = discriminant(_2);
switchInt(move _4) -> [1: bb2, otherwise: bb1]; switchInt(move _4) -> [1: bb7, otherwise: bb2];
} }
bb1: { bb1: {
falseEdge -> [real: bb13, imaginary: bb6]; FakeRead(ForMatchedPlace(None), _2);
unreachable;
} }
bb2: { bb2: {
falseEdge -> [real: bb8, imaginary: bb1]; falseEdge -> [real: bb14, imaginary: bb5];
} }
bb3: { bb3: {
goto -> bb1; _3 = discriminant(_2);
switchInt(move _3) -> [1: bb5, otherwise: bb4];
} }
bb4: { bb4: {
_3 = discriminant(_2);
switchInt(move _3) -> [1: bb6, otherwise: bb5];
}
bb5: {
StorageLive(_14); StorageLive(_14);
_14 = _2; _14 = _2;
_1 = const 4_i32; _1 = const 4_i32;
StorageDead(_14); StorageDead(_14);
goto -> bb19; goto -> bb20;
}
bb5: {
falseEdge -> [real: bb15, imaginary: bb4];
} }
bb6: { bb6: {
falseEdge -> [real: bb14, imaginary: bb5]; goto -> bb4;
} }
bb7: { bb7: {
goto -> bb5; falseEdge -> [real: bb9, imaginary: bb2];
} }
bb8: { bb8: {
goto -> bb2;
}
bb9: {
StorageLive(_7); StorageLive(_7);
_7 = &((_2 as Some).0: i32); _7 = &((_2 as Some).0: i32);
_5 = &fake _2; _5 = &fake _2;
StorageLive(_8); StorageLive(_8);
_8 = guard() -> [return: bb9, unwind: bb20]; _8 = guard() -> [return: bb10, unwind: bb22];
}
bb9: {
switchInt(move _8) -> [0: bb11, otherwise: bb10];
} }
bb10: { bb10: {
switchInt(move _8) -> [0: bb12, otherwise: bb11];
}
bb11: {
StorageDead(_8); StorageDead(_8);
FakeRead(ForMatchGuard, _5); FakeRead(ForMatchGuard, _5);
FakeRead(ForGuardBinding, _7); FakeRead(ForGuardBinding, _7);
@ -96,42 +101,42 @@ fn main() -> () {
_1 = const 1_i32; _1 = const 1_i32;
StorageDead(_6); StorageDead(_6);
StorageDead(_7); StorageDead(_7);
goto -> bb19; goto -> bb20;
}
bb11: {
goto -> bb12;
} }
bb12: { bb12: {
StorageDead(_8); goto -> bb13;
StorageDead(_7);
falseEdge -> [real: bb3, imaginary: bb1];
} }
bb13: { bb13: {
StorageDead(_8);
StorageDead(_7);
falseEdge -> [real: bb8, imaginary: bb2];
}
bb14: {
StorageLive(_9); StorageLive(_9);
_9 = _2; _9 = _2;
_1 = const 2_i32; _1 = const 2_i32;
StorageDead(_9); StorageDead(_9);
goto -> bb19; goto -> bb20;
} }
bb14: { bb15: {
StorageLive(_11); StorageLive(_11);
_11 = &((_2 as Some).0: i32); _11 = &((_2 as Some).0: i32);
_5 = &fake _2; _5 = &fake _2;
StorageLive(_12); StorageLive(_12);
StorageLive(_13); StorageLive(_13);
_13 = (*_11); _13 = (*_11);
_12 = guard2(move _13) -> [return: bb15, unwind: bb20]; _12 = guard2(move _13) -> [return: bb16, unwind: bb22];
}
bb15: {
switchInt(move _12) -> [0: bb17, otherwise: bb16];
} }
bb16: { bb16: {
switchInt(move _12) -> [0: bb18, otherwise: bb17];
}
bb17: {
StorageDead(_13); StorageDead(_13);
StorageDead(_12); StorageDead(_12);
FakeRead(ForMatchGuard, _5); FakeRead(ForMatchGuard, _5);
@ -141,21 +146,21 @@ fn main() -> () {
_1 = const 3_i32; _1 = const 3_i32;
StorageDead(_10); StorageDead(_10);
StorageDead(_11); StorageDead(_11);
goto -> bb19; goto -> bb20;
}
bb17: {
goto -> bb18;
} }
bb18: { bb18: {
StorageDead(_13); goto -> bb19;
StorageDead(_12);
StorageDead(_11);
falseEdge -> [real: bb7, imaginary: bb5];
} }
bb19: { bb19: {
StorageDead(_13);
StorageDead(_12);
StorageDead(_11);
falseEdge -> [real: bb6, imaginary: bb4];
}
bb20: {
PlaceMention(_1); PlaceMention(_1);
StorageDead(_2); StorageDead(_2);
StorageDead(_1); StorageDead(_1);
@ -163,7 +168,12 @@ fn main() -> () {
return; return;
} }
bb20 (cleanup): { bb21: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
bb22 (cleanup): {
resume; resume;
} }
} }

View file

@ -6,24 +6,29 @@ fn match_bool(_1: bool) -> usize {
bb0: { bb0: {
PlaceMention(_1); PlaceMention(_1);
switchInt(_1) -> [0: bb2, otherwise: bb1]; switchInt(_1) -> [0: bb2, otherwise: bb3];
} }
bb1: { bb1: {
falseEdge -> [real: bb3, imaginary: bb2]; FakeRead(ForMatchedPlace(None), _1);
unreachable;
} }
bb2: { bb2: {
_0 = const 20_usize; _0 = const 20_usize;
goto -> bb4; goto -> bb5;
} }
bb3: { bb3: {
_0 = const 10_usize; falseEdge -> [real: bb4, imaginary: bb2];
goto -> bb4;
} }
bb4: { bb4: {
_0 = const 10_usize;
goto -> bb5;
}
bb5: {
return; return;
} }
} }

View file

@ -30,7 +30,7 @@ fn move_out_by_subslice() -> () {
StorageLive(_2); StorageLive(_2);
_3 = SizeOf(i32); _3 = SizeOf(i32);
_4 = AlignOf(i32); _4 = AlignOf(i32);
_5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb13];
} }
bb1: { bb1: {
@ -38,7 +38,7 @@ fn move_out_by_subslice() -> () {
_6 = ShallowInitBox(move _5, i32); _6 = ShallowInitBox(move _5, i32);
(*_6) = const 1_i32; (*_6) = const 1_i32;
_2 = move _6; _2 = move _6;
drop(_6) -> [return: bb2, unwind: bb11]; drop(_6) -> [return: bb2, unwind: bb12];
} }
bb2: { bb2: {
@ -46,7 +46,7 @@ fn move_out_by_subslice() -> () {
StorageLive(_7); StorageLive(_7);
_8 = SizeOf(i32); _8 = SizeOf(i32);
_9 = AlignOf(i32); _9 = AlignOf(i32);
_10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb12];
} }
bb3: { bb3: {
@ -54,18 +54,18 @@ fn move_out_by_subslice() -> () {
_11 = ShallowInitBox(move _10, i32); _11 = ShallowInitBox(move _10, i32);
(*_11) = const 2_i32; (*_11) = const 2_i32;
_7 = move _11; _7 = move _11;
drop(_11) -> [return: bb4, unwind: bb10]; drop(_11) -> [return: bb4, unwind: bb11];
} }
bb4: { bb4: {
StorageDead(_11); StorageDead(_11);
_1 = [move _2, move _7]; _1 = [move _2, move _7];
drop(_7) -> [return: bb5, unwind: bb11]; drop(_7) -> [return: bb5, unwind: bb12];
} }
bb5: { bb5: {
StorageDead(_7); StorageDead(_7);
drop(_2) -> [return: bb6, unwind: bb12]; drop(_2) -> [return: bb6, unwind: bb13];
} }
bb6: { bb6: {
@ -75,32 +75,37 @@ fn move_out_by_subslice() -> () {
StorageLive(_12); StorageLive(_12);
_12 = move _1[0..2]; _12 = move _1[0..2];
_0 = const (); _0 = const ();
drop(_12) -> [return: bb7, unwind: bb9]; drop(_12) -> [return: bb8, unwind: bb10];
} }
bb7: { bb7: {
StorageDead(_12); FakeRead(ForMatchedPlace(None), _1);
drop(_1) -> [return: bb8, unwind: bb12]; unreachable;
} }
bb8: { bb8: {
StorageDead(_12);
drop(_1) -> [return: bb9, unwind: bb13];
}
bb9: {
StorageDead(_1); StorageDead(_1);
return; return;
} }
bb9 (cleanup): {
drop(_1) -> [return: bb12, unwind terminate(cleanup)];
}
bb10 (cleanup): { bb10 (cleanup): {
drop(_7) -> [return: bb11, unwind terminate(cleanup)]; drop(_1) -> [return: bb13, unwind terminate(cleanup)];
} }
bb11 (cleanup): { bb11 (cleanup): {
drop(_2) -> [return: bb12, unwind terminate(cleanup)]; drop(_7) -> [return: bb12, unwind terminate(cleanup)];
} }
bb12 (cleanup): { bb12 (cleanup): {
drop(_2) -> [return: bb13, unwind terminate(cleanup)];
}
bb13 (cleanup): {
resume; resume;
} }
} }

View file

@ -30,7 +30,7 @@ fn move_out_from_end() -> () {
StorageLive(_2); StorageLive(_2);
_3 = SizeOf(i32); _3 = SizeOf(i32);
_4 = AlignOf(i32); _4 = AlignOf(i32);
_5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb13];
} }
bb1: { bb1: {
@ -38,7 +38,7 @@ fn move_out_from_end() -> () {
_6 = ShallowInitBox(move _5, i32); _6 = ShallowInitBox(move _5, i32);
(*_6) = const 1_i32; (*_6) = const 1_i32;
_2 = move _6; _2 = move _6;
drop(_6) -> [return: bb2, unwind: bb11]; drop(_6) -> [return: bb2, unwind: bb12];
} }
bb2: { bb2: {
@ -46,7 +46,7 @@ fn move_out_from_end() -> () {
StorageLive(_7); StorageLive(_7);
_8 = SizeOf(i32); _8 = SizeOf(i32);
_9 = AlignOf(i32); _9 = AlignOf(i32);
_10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb12];
} }
bb3: { bb3: {
@ -54,18 +54,18 @@ fn move_out_from_end() -> () {
_11 = ShallowInitBox(move _10, i32); _11 = ShallowInitBox(move _10, i32);
(*_11) = const 2_i32; (*_11) = const 2_i32;
_7 = move _11; _7 = move _11;
drop(_11) -> [return: bb4, unwind: bb10]; drop(_11) -> [return: bb4, unwind: bb11];
} }
bb4: { bb4: {
StorageDead(_11); StorageDead(_11);
_1 = [move _2, move _7]; _1 = [move _2, move _7];
drop(_7) -> [return: bb5, unwind: bb11]; drop(_7) -> [return: bb5, unwind: bb12];
} }
bb5: { bb5: {
StorageDead(_7); StorageDead(_7);
drop(_2) -> [return: bb6, unwind: bb12]; drop(_2) -> [return: bb6, unwind: bb13];
} }
bb6: { bb6: {
@ -75,32 +75,37 @@ fn move_out_from_end() -> () {
StorageLive(_12); StorageLive(_12);
_12 = move _1[1 of 2]; _12 = move _1[1 of 2];
_0 = const (); _0 = const ();
drop(_12) -> [return: bb7, unwind: bb9]; drop(_12) -> [return: bb8, unwind: bb10];
} }
bb7: { bb7: {
StorageDead(_12); FakeRead(ForMatchedPlace(None), _1);
drop(_1) -> [return: bb8, unwind: bb12]; unreachable;
} }
bb8: { bb8: {
StorageDead(_12);
drop(_1) -> [return: bb9, unwind: bb13];
}
bb9: {
StorageDead(_1); StorageDead(_1);
return; return;
} }
bb9 (cleanup): {
drop(_1) -> [return: bb12, unwind terminate(cleanup)];
}
bb10 (cleanup): { bb10 (cleanup): {
drop(_7) -> [return: bb11, unwind terminate(cleanup)]; drop(_1) -> [return: bb13, unwind terminate(cleanup)];
} }
bb11 (cleanup): { bb11 (cleanup): {
drop(_2) -> [return: bb12, unwind terminate(cleanup)]; drop(_7) -> [return: bb12, unwind terminate(cleanup)];
} }
bb12 (cleanup): { bb12 (cleanup): {
drop(_2) -> [return: bb13, unwind terminate(cleanup)];
}
bb13 (cleanup): {
resume; resume;
} }
} }

View file

@ -79,10 +79,14 @@
bb4: { bb4: {
StorageDead(_12); StorageDead(_12);
_14 = discriminant(_11); _14 = discriminant(_11);
switchInt(move _14) -> [0: bb7, 1: bb5, otherwise: bb6]; switchInt(move _14) -> [0: bb7, 1: bb6, otherwise: bb5];
} }
bb5: { bb5: {
unreachable;
}
bb6: {
- StorageLive(_16); - StorageLive(_16);
_16 = ((_11 as Some).0: usize); _16 = ((_11 as Some).0: usize);
StorageLive(_17); StorageLive(_17);
@ -95,10 +99,6 @@
+ assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, _16) -> [success: bb8, unwind unreachable]; + assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, _16) -> [success: bb8, unwind unreachable];
} }
bb6: {
unreachable;
}
bb7: { bb7: {
_0 = const (); _0 = const ();
StorageDead(_13); StorageDead(_13);

View file

@ -79,10 +79,14 @@
bb4: { bb4: {
StorageDead(_12); StorageDead(_12);
_14 = discriminant(_11); _14 = discriminant(_11);
switchInt(move _14) -> [0: bb7, 1: bb5, otherwise: bb6]; switchInt(move _14) -> [0: bb7, 1: bb6, otherwise: bb5];
} }
bb5: { bb5: {
unreachable;
}
bb6: {
- StorageLive(_16); - StorageLive(_16);
_16 = ((_11 as Some).0: usize); _16 = ((_11 as Some).0: usize);
StorageLive(_17); StorageLive(_17);
@ -95,10 +99,6 @@
+ assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, _16) -> [success: bb8, unwind continue]; + assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, _16) -> [success: bb8, unwind continue];
} }
bb6: {
unreachable;
}
bb7: { bb7: {
_0 = const (); _0 = const ();
StorageDead(_13); StorageDead(_13);

View file

@ -26,12 +26,16 @@
_1 = const _; _1 = const _;
StorageLive(_2); StorageLive(_2);
- _3 = discriminant(_1); - _3 = discriminant(_1);
- switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; - switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1];
+ _3 = const 0_isize; + _3 = const 0_isize;
+ switchInt(const 0_isize) -> [0: bb3, 1: bb1, otherwise: bb2]; + switchInt(const 0_isize) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_5); StorageLive(_5);
_5 = ((_1 as V2).0: i32); _5 = ((_1 as V2).0: i32);
_2 = _5; _2 = _5;
@ -39,10 +43,6 @@
goto -> bb4; goto -> bb4;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
StorageLive(_4); StorageLive(_4);
- _4 = ((_1 as V1).0: i32); - _4 = ((_1 as V1).0: i32);

View file

@ -26,12 +26,16 @@
_1 = const _; _1 = const _;
StorageLive(_2); StorageLive(_2);
- _3 = discriminant(_1); - _3 = discriminant(_1);
- switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; - switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1];
+ _3 = const 0_isize; + _3 = const 0_isize;
+ switchInt(const 0_isize) -> [0: bb3, 1: bb1, otherwise: bb2]; + switchInt(const 0_isize) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_5); StorageLive(_5);
_5 = ((_1 as V2).0: i32); _5 = ((_1 as V2).0: i32);
_2 = _5; _2 = _5;
@ -39,10 +43,6 @@
goto -> bb4; goto -> bb4;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
StorageLive(_4); StorageLive(_4);
- _4 = ((_1 as V1).0: i32); - _4 = ((_1 as V1).0: i32);

View file

@ -49,16 +49,16 @@
StorageDead(_4); StorageDead(_4);
StorageLive(_6); StorageLive(_6);
_7 = discriminant(_3); _7 = discriminant(_3);
switchInt(move _7) -> [0: bb4, 1: bb6, otherwise: bb5]; switchInt(move _7) -> [0: bb5, 1: bb6, otherwise: bb4];
} }
bb4: { bb4: {
_6 = const 0_u8; unreachable;
goto -> bb7;
} }
bb5: { bb5: {
unreachable; _6 = const 0_u8;
goto -> bb7;
} }
bb6: { bb6: {

View file

@ -49,16 +49,16 @@
StorageDead(_4); StorageDead(_4);
StorageLive(_6); StorageLive(_6);
_7 = discriminant(_3); _7 = discriminant(_3);
switchInt(move _7) -> [0: bb4, 1: bb6, otherwise: bb5]; switchInt(move _7) -> [0: bb5, 1: bb6, otherwise: bb4];
} }
bb4: { bb4: {
_6 = const 0_u8; unreachable;
goto -> bb7;
} }
bb5: { bb5: {
unreachable; _6 = const 0_u8;
goto -> bb7;
} }
bb6: { bb6: {

View file

@ -20,7 +20,7 @@ fn simple() {
// CHECK: [[e]] = const E::V1(0_i32); // CHECK: [[e]] = const E::V1(0_i32);
let e = E::V1(0); let e = E::V1(0);
// CHECK: switchInt(const 0_isize) -> [0: [[target_bb:bb.*]], 1: bb1, otherwise: bb2]; // CHECK: switchInt(const 0_isize) -> [0: [[target_bb:bb.*]], 1: bb2, otherwise: bb1];
// CHECK: [[target_bb]]: { // CHECK: [[target_bb]]: {
// CHECK: [[x]] = const 0_i32; // CHECK: [[x]] = const 0_i32;
let x = match e { E::V1(x1) => x1, E::V2(x2) => x2 }; let x = match e { E::V1(x1) => x1, E::V2(x2) => x2 };
@ -36,7 +36,7 @@ fn constant() {
// CHECK: [[e]] = const _; // CHECK: [[e]] = const _;
let e = C; let e = C;
// CHECK: switchInt(const 0_isize) -> [0: [[target_bb:bb.*]], 1: bb1, otherwise: bb2]; // CHECK: switchInt(const 0_isize) -> [0: [[target_bb:bb.*]], 1: bb2, otherwise: bb1];
// CHECK: [[target_bb]]: { // CHECK: [[target_bb]]: {
// CHECK: [[x]] = const 0_i32; // CHECK: [[x]] = const 0_i32;
let x = match e { E::V1(x1) => x1, E::V2(x2) => x2 }; let x = match e { E::V1(x1) => x1, E::V2(x2) => x2 };
@ -55,7 +55,7 @@ fn statics() {
// CHECK: [[e1]] = const E::V1(0_i32); // CHECK: [[e1]] = const E::V1(0_i32);
let e1 = C; let e1 = C;
// CHECK: switchInt(const 0_isize) -> [0: [[target_bb:bb.*]], 1: bb1, otherwise: bb2]; // CHECK: switchInt(const 0_isize) -> [0: [[target_bb:bb.*]], 1: bb2, otherwise: bb1];
// CHECK: [[target_bb]]: { // CHECK: [[target_bb]]: {
// CHECK: [[x1]] = const 0_i32; // CHECK: [[x1]] = const 0_i32;
let x1 = match e1 { E::V1(x11) => x11, E::V2(x12) => x12 }; let x1 = match e1 { E::V1(x11) => x11, E::V2(x12) => x12 };

View file

@ -27,12 +27,16 @@
+ _1 = const E::V1(0_i32); + _1 = const E::V1(0_i32);
StorageLive(_2); StorageLive(_2);
- _3 = discriminant(_1); - _3 = discriminant(_1);
- switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; - switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1];
+ _3 = const 0_isize; + _3 = const 0_isize;
+ switchInt(const 0_isize) -> [0: bb3, 1: bb1, otherwise: bb2]; + switchInt(const 0_isize) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_5); StorageLive(_5);
_5 = ((_1 as V2).0: i32); _5 = ((_1 as V2).0: i32);
_2 = _5; _2 = _5;
@ -40,10 +44,6 @@
goto -> bb4; goto -> bb4;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
StorageLive(_4); StorageLive(_4);
- _4 = ((_1 as V1).0: i32); - _4 = ((_1 as V1).0: i32);

View file

@ -27,12 +27,16 @@
+ _1 = const E::V1(0_i32); + _1 = const E::V1(0_i32);
StorageLive(_2); StorageLive(_2);
- _3 = discriminant(_1); - _3 = discriminant(_1);
- switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; - switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1];
+ _3 = const 0_isize; + _3 = const 0_isize;
+ switchInt(const 0_isize) -> [0: bb3, 1: bb1, otherwise: bb2]; + switchInt(const 0_isize) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_5); StorageLive(_5);
_5 = ((_1 as V2).0: i32); _5 = ((_1 as V2).0: i32);
_2 = _5; _2 = _5;
@ -40,10 +44,6 @@
goto -> bb4; goto -> bb4;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
StorageLive(_4); StorageLive(_4);
- _4 = ((_1 as V1).0: i32); - _4 = ((_1 as V1).0: i32);

View file

@ -49,12 +49,16 @@
StorageDead(_2); StorageDead(_2);
StorageLive(_3); StorageLive(_3);
- _4 = discriminant(_1); - _4 = discriminant(_1);
- switchInt(move _4) -> [0: bb3, 1: bb1, otherwise: bb2]; - switchInt(move _4) -> [0: bb3, 1: bb2, otherwise: bb1];
+ _4 = const 0_isize; + _4 = const 0_isize;
+ switchInt(const 0_isize) -> [0: bb3, 1: bb1, otherwise: bb2]; + switchInt(const 0_isize) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_6); StorageLive(_6);
_6 = ((_1 as V2).0: i32); _6 = ((_1 as V2).0: i32);
_3 = _6; _3 = _6;
@ -62,10 +66,6 @@
goto -> bb4; goto -> bb4;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
StorageLive(_5); StorageLive(_5);
- _5 = ((_1 as V1).0: i32); - _5 = ((_1 as V1).0: i32);
@ -84,7 +84,7 @@
StorageDead(_8); StorageDead(_8);
StorageLive(_9); StorageLive(_9);
_10 = discriminant((*_7)); _10 = discriminant((*_7));
switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb2]; switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb1];
} }
bb5: { bb5: {

View file

@ -49,12 +49,16 @@
StorageDead(_2); StorageDead(_2);
StorageLive(_3); StorageLive(_3);
- _4 = discriminant(_1); - _4 = discriminant(_1);
- switchInt(move _4) -> [0: bb3, 1: bb1, otherwise: bb2]; - switchInt(move _4) -> [0: bb3, 1: bb2, otherwise: bb1];
+ _4 = const 0_isize; + _4 = const 0_isize;
+ switchInt(const 0_isize) -> [0: bb3, 1: bb1, otherwise: bb2]; + switchInt(const 0_isize) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_6); StorageLive(_6);
_6 = ((_1 as V2).0: i32); _6 = ((_1 as V2).0: i32);
_3 = _6; _3 = _6;
@ -62,10 +66,6 @@
goto -> bb4; goto -> bb4;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
StorageLive(_5); StorageLive(_5);
- _5 = ((_1 as V1).0: i32); - _5 = ((_1 as V1).0: i32);
@ -84,7 +84,7 @@
StorageDead(_8); StorageDead(_8);
StorageLive(_9); StorageLive(_9);
_10 = discriminant((*_7)); _10 = discriminant((*_7));
switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb2]; switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb1];
} }
bb5: { bb5: {

View file

@ -25,58 +25,66 @@
_7 = Len((*_2)); _7 = Len((*_2));
_8 = const 4_usize; _8 = const 4_usize;
_9 = Ge(move _7, move _8); _9 = Ge(move _7, move _8);
switchInt(move _9) -> [0: bb6, otherwise: bb2]; - switchInt(move _9) -> [0: bb2, otherwise: bb7];
+ switchInt(move _9) -> [0: bb2, otherwise: bb6];
} }
bb2: { bb2: {
switchInt((*_2)[0 of 4]) -> [47: bb3, otherwise: bb6];
}
bb3: {
switchInt((*_2)[1 of 4]) -> [47: bb4, otherwise: bb6];
}
bb4: {
switchInt((*_2)[2 of 4]) -> [47: bb5, otherwise: bb6];
}
bb5: {
- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb6];
+ switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb6];
}
bb6: {
_4 = Len((*_2)); _4 = Len((*_2));
_5 = const 3_usize; _5 = const 3_usize;
_6 = Ge(move _4, move _5); _6 = Ge(move _4, move _5);
switchInt(move _6) -> [0: bb10, otherwise: bb7]; - switchInt(move _6) -> [0: bb3, otherwise: bb4];
+ switchInt(move _6) -> [0: bb10, otherwise: bb3];
} }
bb7: { bb3: {
switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb10]; - _0 = const false;
- goto -> bb14;
+ switchInt((*_2)[0 of 3]) -> [47: bb4, otherwise: bb10];
} }
bb8: { bb4: {
switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb10]; - switchInt((*_2)[0 of 3]) -> [47: bb5, otherwise: bb3];
+ switchInt((*_2)[1 of 3]) -> [47: bb5, otherwise: bb10];
} }
bb9: { bb5: {
- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb10]; - switchInt((*_2)[1 of 3]) -> [47: bb6, otherwise: bb3];
+ switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; + switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10];
} }
bb6: {
- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb3];
+ switchInt((*_2)[0 of 4]) -> [47: bb7, otherwise: bb2];
}
bb7: {
- switchInt((*_2)[0 of 4]) -> [47: bb8, otherwise: bb2];
+ switchInt((*_2)[1 of 4]) -> [47: bb8, otherwise: bb2];
}
bb8: {
- switchInt((*_2)[1 of 4]) -> [47: bb9, otherwise: bb2];
+ switchInt((*_2)[2 of 4]) -> [47: bb9, otherwise: bb2];
}
bb9: {
- switchInt((*_2)[2 of 4]) -> [47: bb10, otherwise: bb2];
+ switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb2];
}
bb10: { bb10: {
- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2];
- }
-
- bb11: {
_0 = const false; _0 = const false;
- goto -> bb14; - goto -> bb14;
+ goto -> bb12; + goto -> bb12;
} }
bb11: {
- _0 = const false;
- goto -> bb14;
- }
-
- bb12: { - bb12: {
+ bb11: {
_0 = const true; _0 = const true;
- goto -> bb14; - goto -> bb14;
+ goto -> bb12; + goto -> bb12;

View file

@ -25,58 +25,66 @@
_7 = Len((*_2)); _7 = Len((*_2));
_8 = const 4_usize; _8 = const 4_usize;
_9 = Ge(move _7, move _8); _9 = Ge(move _7, move _8);
switchInt(move _9) -> [0: bb6, otherwise: bb2]; - switchInt(move _9) -> [0: bb2, otherwise: bb7];
+ switchInt(move _9) -> [0: bb2, otherwise: bb6];
} }
bb2: { bb2: {
switchInt((*_2)[0 of 4]) -> [47: bb3, otherwise: bb6];
}
bb3: {
switchInt((*_2)[1 of 4]) -> [47: bb4, otherwise: bb6];
}
bb4: {
switchInt((*_2)[2 of 4]) -> [47: bb5, otherwise: bb6];
}
bb5: {
- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb6];
+ switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb6];
}
bb6: {
_4 = Len((*_2)); _4 = Len((*_2));
_5 = const 3_usize; _5 = const 3_usize;
_6 = Ge(move _4, move _5); _6 = Ge(move _4, move _5);
switchInt(move _6) -> [0: bb10, otherwise: bb7]; - switchInt(move _6) -> [0: bb3, otherwise: bb4];
+ switchInt(move _6) -> [0: bb10, otherwise: bb3];
} }
bb7: { bb3: {
switchInt((*_2)[0 of 3]) -> [47: bb8, otherwise: bb10]; - _0 = const false;
- goto -> bb14;
+ switchInt((*_2)[0 of 3]) -> [47: bb4, otherwise: bb10];
} }
bb8: { bb4: {
switchInt((*_2)[1 of 3]) -> [47: bb9, otherwise: bb10]; - switchInt((*_2)[0 of 3]) -> [47: bb5, otherwise: bb3];
+ switchInt((*_2)[1 of 3]) -> [47: bb5, otherwise: bb10];
} }
bb9: { bb5: {
- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb10]; - switchInt((*_2)[1 of 3]) -> [47: bb6, otherwise: bb3];
+ switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10]; + switchInt((*_2)[2 of 3]) -> [47: bb11, 33: bb11, otherwise: bb10];
} }
bb6: {
- switchInt((*_2)[2 of 3]) -> [47: bb12, 33: bb13, otherwise: bb3];
+ switchInt((*_2)[0 of 4]) -> [47: bb7, otherwise: bb2];
}
bb7: {
- switchInt((*_2)[0 of 4]) -> [47: bb8, otherwise: bb2];
+ switchInt((*_2)[1 of 4]) -> [47: bb8, otherwise: bb2];
}
bb8: {
- switchInt((*_2)[1 of 4]) -> [47: bb9, otherwise: bb2];
+ switchInt((*_2)[2 of 4]) -> [47: bb9, otherwise: bb2];
}
bb9: {
- switchInt((*_2)[2 of 4]) -> [47: bb10, otherwise: bb2];
+ switchInt((*_2)[3 of 4]) -> [47: bb10, otherwise: bb2];
}
bb10: { bb10: {
- switchInt((*_2)[3 of 4]) -> [47: bb11, otherwise: bb2];
- }
-
- bb11: {
_0 = const false; _0 = const false;
- goto -> bb14; - goto -> bb14;
+ goto -> bb12; + goto -> bb12;
} }
bb11: {
- _0 = const false;
- goto -> bb14;
- }
-
- bb12: { - bb12: {
+ bb11: {
_0 = const true; _0 = const true;
- goto -> bb14; - goto -> bb14;
+ goto -> bb12; + goto -> bb12;

View file

@ -55,10 +55,14 @@
StorageDead(_8); StorageDead(_8);
PlaceMention(_7); PlaceMention(_7);
_10 = discriminant(_7); _10 = discriminant(_7);
switchInt(move _10) -> [0: bb6, 1: bb4, otherwise: bb5]; switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb4];
} }
bb4: { bb4: {
unreachable;
}
bb5: {
StorageLive(_12); StorageLive(_12);
- _12 = (*((_7 as Some).0: &i32)); - _12 = (*((_7 as Some).0: &i32));
+ _15 = deref_copy ((_7 as Some).0: &i32); + _15 = deref_copy ((_7 as Some).0: &i32);
@ -68,10 +72,6 @@
_6 = std::mem::drop::<i32>(move _13) -> [return: bb7, unwind: bb8]; _6 = std::mem::drop::<i32>(move _13) -> [return: bb7, unwind: bb8];
} }
bb5: {
unreachable;
}
bb6: { bb6: {
_0 = const (); _0 = const ();
StorageDead(_9); StorageDead(_9);

View file

@ -55,10 +55,14 @@
StorageDead(_8); StorageDead(_8);
PlaceMention(_7); PlaceMention(_7);
_10 = discriminant(_7); _10 = discriminant(_7);
switchInt(move _10) -> [0: bb6, 1: bb4, otherwise: bb5]; switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb4];
} }
bb4: { bb4: {
unreachable;
}
bb5: {
StorageLive(_12); StorageLive(_12);
- _12 = (*((_7 as Some).0: &i32)); - _12 = (*((_7 as Some).0: &i32));
+ _15 = deref_copy ((_7 as Some).0: &i32); + _15 = deref_copy ((_7 as Some).0: &i32);
@ -68,10 +72,6 @@
_6 = std::mem::drop::<i32>(move _13) -> [return: bb7, unwind continue]; _6 = std::mem::drop::<i32>(move _13) -> [return: bb7, unwind continue];
} }
bb5: {
unreachable;
}
bb6: { bb6: {
_0 = const (); _0 = const ();
StorageDead(_9); StorageDead(_9);

View file

@ -30,7 +30,7 @@
StorageDead(_5); StorageDead(_5);
StorageDead(_4); StorageDead(_4);
_8 = discriminant((_3.0: std::option::Option<u32>)); _8 = discriminant((_3.0: std::option::Option<u32>));
- switchInt(move _8) -> [0: bb1, 1: bb3, otherwise: bb2]; - switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1];
+ StorageLive(_11); + StorageLive(_11);
+ _11 = discriminant((_3.1: std::option::Option<u32>)); + _11 = discriminant((_3.1: std::option::Option<u32>));
+ StorageLive(_12); + StorageLive(_12);
@ -40,24 +40,23 @@
} }
bb1: { bb1: {
- _6 = discriminant((_3.1: std::option::Option<u32>));
- switchInt(move _6) -> [0: bb5, otherwise: bb2];
- }
-
- bb2: {
+ StorageDead(_12); + StorageDead(_12);
_0 = const 1_u32; _0 = const 1_u32;
- goto -> bb6; - goto -> bb6;
+ goto -> bb4; + goto -> bb4;
} }
bb2: {
- _6 = discriminant((_3.1: std::option::Option<u32>));
- switchInt(move _6) -> [0: bb5, otherwise: bb1];
- }
-
- bb3: { - bb3: {
- _7 = discriminant((_3.1: std::option::Option<u32>)); - _7 = discriminant((_3.1: std::option::Option<u32>));
- switchInt(move _7) -> [1: bb4, otherwise: bb2]; - switchInt(move _7) -> [1: bb4, otherwise: bb1];
- } - }
- -
- bb4: { - bb4: {
+ bb2: {
StorageLive(_10); StorageLive(_10);
_10 = (((_3.1: std::option::Option<u32>) as Some).0: u32); _10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
StorageLive(_9); StorageLive(_9);

View file

@ -78,16 +78,10 @@
StorageDead(_5); StorageDead(_5);
_34 = deref_copy (_4.0: &ViewportPercentageLength); _34 = deref_copy (_4.0: &ViewportPercentageLength);
_11 = discriminant((*_34)); _11 = discriminant((*_34));
switchInt(move _11) -> [0: bb1, 1: bb3, 2: bb4, 3: bb5, otherwise: bb2]; switchInt(move _11) -> [0: bb2, 1: bb3, 2: bb4, 3: bb5, otherwise: bb1];
} }
bb1: { bb1: {
_35 = deref_copy (_4.1: &ViewportPercentageLength);
_7 = discriminant((*_35));
switchInt(move _7) -> [0: bb6, otherwise: bb2];
}
bb2: {
StorageLive(_33); StorageLive(_33);
_33 = (); _33 = ();
_0 = Result::<ViewportPercentageLength, ()>::Err(move _33); _0 = Result::<ViewportPercentageLength, ()>::Err(move _33);
@ -97,22 +91,28 @@
goto -> bb11; goto -> bb11;
} }
bb2: {
_35 = deref_copy (_4.1: &ViewportPercentageLength);
_7 = discriminant((*_35));
switchInt(move _7) -> [0: bb6, otherwise: bb1];
}
bb3: { bb3: {
_36 = deref_copy (_4.1: &ViewportPercentageLength); _36 = deref_copy (_4.1: &ViewportPercentageLength);
_8 = discriminant((*_36)); _8 = discriminant((*_36));
switchInt(move _8) -> [1: bb7, otherwise: bb2]; switchInt(move _8) -> [1: bb7, otherwise: bb1];
} }
bb4: { bb4: {
_37 = deref_copy (_4.1: &ViewportPercentageLength); _37 = deref_copy (_4.1: &ViewportPercentageLength);
_9 = discriminant((*_37)); _9 = discriminant((*_37));
switchInt(move _9) -> [2: bb8, otherwise: bb2]; switchInt(move _9) -> [2: bb8, otherwise: bb1];
} }
bb5: { bb5: {
_38 = deref_copy (_4.1: &ViewportPercentageLength); _38 = deref_copy (_4.1: &ViewportPercentageLength);
_10 = discriminant((*_38)); _10 = discriminant((*_38));
switchInt(move _10) -> [3: bb9, otherwise: bb2]; switchInt(move _10) -> [3: bb9, otherwise: bb1];
} }
bb6: { bb6: {

View file

@ -36,26 +36,26 @@
StorageDead(_5); StorageDead(_5);
StorageDead(_4); StorageDead(_4);
_8 = discriminant((_3.0: std::option::Option<u32>)); _8 = discriminant((_3.0: std::option::Option<u32>));
switchInt(move _8) -> [0: bb1, 1: bb4, otherwise: bb3]; switchInt(move _8) -> [0: bb2, 1: bb4, otherwise: bb1];
} }
bb1: { bb1: {
_6 = discriminant((_3.1: std::option::Option<u32>)); unreachable;
switchInt(move _6) -> [0: bb2, 1: bb7, otherwise: bb3];
} }
bb2: { bb2: {
_6 = discriminant((_3.1: std::option::Option<u32>));
switchInt(move _6) -> [0: bb3, 1: bb7, otherwise: bb1];
}
bb3: {
_0 = const 3_u32; _0 = const 3_u32;
goto -> bb8; goto -> bb8;
} }
bb3: {
unreachable;
}
bb4: { bb4: {
_7 = discriminant((_3.1: std::option::Option<u32>)); _7 = discriminant((_3.1: std::option::Option<u32>));
switchInt(move _7) -> [0: bb6, 1: bb5, otherwise: bb3]; switchInt(move _7) -> [0: bb6, 1: bb5, otherwise: bb1];
} }
bb5: { bb5: {

View file

@ -21,18 +21,18 @@
+ _2 = Option::<T>::Some(_1); + _2 = Option::<T>::Some(_1);
StorageDead(_3); StorageDead(_3);
- _4 = discriminant(_2); - _4 = discriminant(_2);
- switchInt(move _4) -> [0: bb1, 1: bb3, otherwise: bb2]; - switchInt(move _4) -> [0: bb2, 1: bb3, otherwise: bb1];
+ _4 = const 1_isize; + _4 = const 1_isize;
+ switchInt(const 1_isize) -> [0: bb1, 1: bb3, otherwise: bb2]; + switchInt(const 1_isize) -> [0: bb2, 1: bb3, otherwise: bb1];
} }
bb1: { bb1: {
StorageLive(_6); unreachable;
_6 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable;
} }
bb2: { bb2: {
unreachable; StorageLive(_6);
_6 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable;
} }
bb3: { bb3: {

View file

@ -21,18 +21,18 @@
+ _2 = Option::<T>::Some(_1); + _2 = Option::<T>::Some(_1);
StorageDead(_3); StorageDead(_3);
- _4 = discriminant(_2); - _4 = discriminant(_2);
- switchInt(move _4) -> [0: bb1, 1: bb3, otherwise: bb2]; - switchInt(move _4) -> [0: bb2, 1: bb3, otherwise: bb1];
+ _4 = const 1_isize; + _4 = const 1_isize;
+ switchInt(const 1_isize) -> [0: bb1, 1: bb3, otherwise: bb2]; + switchInt(const 1_isize) -> [0: bb2, 1: bb3, otherwise: bb1];
} }
bb1: { bb1: {
StorageLive(_6); unreachable;
_6 = begin_panic::<&str>(const "explicit panic") -> unwind continue;
} }
bb2: { bb2: {
unreachable; StorageLive(_6);
_6 = begin_panic::<&str>(const "explicit panic") -> unwind continue;
} }
bb3: { bb3: {

View file

@ -28,18 +28,18 @@
+ StorageLive(_3); + StorageLive(_3);
+ StorageLive(_5); + StorageLive(_5);
+ _3 = discriminant(_2); + _3 = discriminant(_2);
+ switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2]; + switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
} }
bb1: { bb1: {
+ StorageLive(_4); + unreachable;
+ _4 = cfg!(debug_assertions);
+ assume(_4);
+ _5 = unreachable_unchecked::precondition_check() -> [return: bb2, unwind unreachable];
+ } + }
+ +
+ bb2: { + bb2: {
+ unreachable; + StorageLive(_4);
+ _4 = cfg!(debug_assertions);
+ assume(_4);
+ _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable];
+ } + }
+ +
+ bb3: { + bb3: {

View file

@ -28,22 +28,22 @@
+ StorageLive(_3); + StorageLive(_3);
+ StorageLive(_5); + StorageLive(_5);
+ _3 = discriminant(_2); + _3 = discriminant(_2);
+ switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2]; + switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
} }
bb1: { bb1: {
- StorageDead(_2); - StorageDead(_2);
- return; - return;
+ StorageLive(_4); + unreachable;
+ _4 = cfg!(debug_assertions);
+ assume(_4);
+ _5 = unreachable_unchecked::precondition_check() -> [return: bb2, unwind unreachable];
} }
- bb2 (cleanup): { - bb2 (cleanup): {
- resume; - resume;
+ bb2: { + bb2: {
+ unreachable; + StorageLive(_4);
+ _4 = cfg!(debug_assertions);
+ assume(_4);
+ _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable];
+ } + }
+ +
+ bb3: { + bb3: {

View file

@ -47,10 +47,14 @@ fn test() -> Option<Box<u32>> {
StorageDead(_7); StorageDead(_7);
PlaceMention(_6); PlaceMention(_6);
_8 = discriminant(_6); _8 = discriminant(_6);
switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb4]; switchInt(move _8) -> [0: bb4, 1: bb5, otherwise: bb3];
} }
bb3: { bb3: {
unreachable;
}
bb4: {
StorageLive(_12); StorageLive(_12);
_12 = ((_6 as Continue).0: u32); _12 = ((_6 as Continue).0: u32);
(*_5) = _12; (*_5) = _12;
@ -59,10 +63,6 @@ fn test() -> Option<Box<u32>> {
drop(_5) -> [return: bb7, unwind: bb11]; drop(_5) -> [return: bb7, unwind: bb11];
} }
bb4: {
unreachable;
}
bb5: { bb5: {
StorageLive(_9); StorageLive(_9);
_9 = ((_6 as Break).0: std::option::Option<std::convert::Infallible>); _9 = ((_6 as Break).0: std::option::Option<std::convert::Infallible>);

View file

@ -47,10 +47,14 @@ fn test() -> Option<Box<u32>> {
StorageDead(_7); StorageDead(_7);
PlaceMention(_6); PlaceMention(_6);
_8 = discriminant(_6); _8 = discriminant(_6);
switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb4]; switchInt(move _8) -> [0: bb4, 1: bb5, otherwise: bb3];
} }
bb3: { bb3: {
unreachable;
}
bb4: {
StorageLive(_12); StorageLive(_12);
_12 = ((_6 as Continue).0: u32); _12 = ((_6 as Continue).0: u32);
(*_5) = _12; (*_5) = _12;
@ -59,10 +63,6 @@ fn test() -> Option<Box<u32>> {
drop(_5) -> [return: bb7, unwind: bb11]; drop(_5) -> [return: bb7, unwind: bb11];
} }
bb4: {
unreachable;
}
bb5: { bb5: {
StorageLive(_9); StorageLive(_9);
_9 = ((_6 as Break).0: std::option::Option<std::convert::Infallible>); _9 = ((_6 as Break).0: std::option::Option<std::convert::Infallible>);

View file

@ -14,4 +14,9 @@ fn bar(_1: [(Never, u32); 1]) -> u32 {
StorageDead(_2); StorageDead(_2);
return; return;
} }
bb1: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
} }

View file

@ -22,7 +22,7 @@ fn main() -> () {
bb0: { bb0: {
StorageLive(_1); StorageLive(_1);
_1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb5];
} }
bb1: { bb1: {
@ -42,10 +42,15 @@ fn main() -> () {
_6 = const 0_usize; _6 = const 0_usize;
_7 = Len(_2); _7 = Len(_2);
_8 = Lt(_6, _7); _8 = Lt(_6, _7);
assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb5];
} }
bb2: { bb2: {
FakeRead(ForMatchedPlace(None), _1);
unreachable;
}
bb3: {
_5 = (_2[_6].0: u64); _5 = (_2[_6].0: u64);
PlaceMention(_5); PlaceMention(_5);
StorageDead(_6); StorageDead(_6);
@ -55,7 +60,12 @@ fn main() -> () {
return; return;
} }
bb3 (cleanup): { bb4: {
FakeRead(ForMatchedPlace(None), _5);
unreachable;
}
bb5 (cleanup): {
resume; resume;
} }
} }

View file

@ -6,11 +6,15 @@ fn f(_1: Void) -> ! {
bb0: { bb0: {
PlaceMention(_1); PlaceMention(_1);
goto -> bb1;
}
bb1: {
FakeRead(ForMatchedPlace(None), _1); FakeRead(ForMatchedPlace(None), _1);
unreachable; unreachable;
} }
bb1: { bb2: {
return; return;
} }
} }

View file

@ -12,7 +12,7 @@ fn bar(_1: Box<[T]>) -> () {
StorageLive(_2); StorageLive(_2);
StorageLive(_3); StorageLive(_3);
_3 = &(*_1); _3 = &(*_1);
_2 = <[T] as Index<usize>>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb3]; _2 = <[T] as Index<usize>>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb4];
} }
bb1: { bb1: {
@ -20,18 +20,23 @@ fn bar(_1: Box<[T]>) -> () {
PlaceMention((*_2)); PlaceMention((*_2));
StorageDead(_2); StorageDead(_2);
_0 = const (); _0 = const ();
drop(_1) -> [return: bb2, unwind: bb4]; drop(_1) -> [return: bb3, unwind: bb5];
} }
bb2: { bb2: {
FakeRead(ForMatchedPlace(None), (*_2));
unreachable;
}
bb3: {
return; return;
} }
bb3 (cleanup): { bb4 (cleanup): {
drop(_1) -> [return: bb4, unwind terminate(cleanup)]; drop(_1) -> [return: bb5, unwind terminate(cleanup)];
} }
bb4 (cleanup): { bb5 (cleanup): {
resume; resume;
} }
} }

View file

@ -14,7 +14,7 @@ fn hey(_1: &[T]) -> () {
StorageLive(_3); StorageLive(_3);
StorageLive(_4); StorageLive(_4);
_4 = &(*_1); _4 = &(*_1);
_3 = <[T] as Index<usize>>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb2]; _3 = <[T] as Index<usize>>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb3];
} }
bb1: { bb1: {
@ -27,7 +27,12 @@ fn hey(_1: &[T]) -> () {
return; return;
} }
bb2 (cleanup): { bb2: {
FakeRead(ForMatchedPlace(None), _2);
unreachable;
}
bb3 (cleanup): {
resume; resume;
} }
} }

View file

@ -67,7 +67,7 @@ fn main() -> () {
StorageLive(_2); StorageLive(_2);
StorageLive(_3); StorageLive(_3);
StorageLive(_4); StorageLive(_4);
_4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb21]; _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb23];
} }
bb1: { bb1: {
@ -91,24 +91,29 @@ fn main() -> () {
_11 = &(*_8); _11 = &(*_8);
StorageLive(_12); StorageLive(_12);
_12 = &(*_9); _12 = &(*_9);
_10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb2, unwind: bb21]; _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb3, unwind: bb23];
} }
bb2: { bb2: {
switchInt(move _10) -> [0: bb4, otherwise: bb3]; FakeRead(ForMatchedPlace(None), _2);
unreachable;
} }
bb3: { bb3: {
StorageDead(_12); switchInt(move _10) -> [0: bb5, otherwise: bb4];
StorageDead(_11);
goto -> bb8;
} }
bb4: { bb4: {
goto -> bb5; StorageDead(_12);
StorageDead(_11);
goto -> bb9;
} }
bb5: { bb5: {
goto -> bb6;
}
bb6: {
StorageDead(_12); StorageDead(_12);
StorageDead(_11); StorageDead(_11);
StorageLive(_14); StorageLive(_14);
@ -127,10 +132,10 @@ fn main() -> () {
_19 = &(*_20); _19 = &(*_20);
StorageLive(_21); StorageLive(_21);
_21 = Option::<Arguments<'_>>::None; _21 = Option::<Arguments<'_>>::None;
_15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb21; _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb23;
} }
bb6: { bb7: {
StorageDead(_21); StorageDead(_21);
StorageDead(_19); StorageDead(_19);
StorageDead(_17); StorageDead(_17);
@ -142,23 +147,23 @@ fn main() -> () {
unreachable; unreachable;
} }
bb7: {
goto -> bb9;
}
bb8: { bb8: {
_1 = const (); goto -> bb10;
goto -> bb9;
} }
bb9: { bb9: {
StorageDead(_10); _1 = const ();
StorageDead(_9);
StorageDead(_8);
goto -> bb10; goto -> bb10;
} }
bb10: { bb10: {
StorageDead(_10);
StorageDead(_9);
StorageDead(_8);
goto -> bb11;
}
bb11: {
StorageDead(_7); StorageDead(_7);
StorageDead(_6); StorageDead(_6);
StorageDead(_4); StorageDead(_4);
@ -168,10 +173,10 @@ fn main() -> () {
StorageLive(_23); StorageLive(_23);
StorageLive(_24); StorageLive(_24);
StorageLive(_25); StorageLive(_25);
_25 = function_with_bytes::<&*b"AAAA">() -> [return: bb11, unwind: bb21]; _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb12, unwind: bb23];
} }
bb11: { bb12: {
_24 = &_25; _24 = &_25;
StorageLive(_26); StorageLive(_26);
StorageLive(_27); StorageLive(_27);
@ -190,24 +195,29 @@ fn main() -> () {
_31 = &(*_28); _31 = &(*_28);
StorageLive(_32); StorageLive(_32);
_32 = &(*_29); _32 = &(*_29);
_30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb12, unwind: bb21]; _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb14, unwind: bb23];
}
bb12: {
switchInt(move _30) -> [0: bb14, otherwise: bb13];
} }
bb13: { bb13: {
StorageDead(_32); FakeRead(ForMatchedPlace(None), _23);
StorageDead(_31); unreachable;
goto -> bb18;
} }
bb14: { bb14: {
goto -> bb15; switchInt(move _30) -> [0: bb16, otherwise: bb15];
} }
bb15: { bb15: {
StorageDead(_32);
StorageDead(_31);
goto -> bb20;
}
bb16: {
goto -> bb17;
}
bb17: {
StorageDead(_32); StorageDead(_32);
StorageDead(_31); StorageDead(_31);
StorageLive(_34); StorageLive(_34);
@ -226,10 +236,10 @@ fn main() -> () {
_39 = &(*_40); _39 = &(*_40);
StorageLive(_41); StorageLive(_41);
_41 = Option::<Arguments<'_>>::None; _41 = Option::<Arguments<'_>>::None;
_35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb21; _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb23;
} }
bb16: { bb18: {
StorageDead(_41); StorageDead(_41);
StorageDead(_39); StorageDead(_39);
StorageDead(_37); StorageDead(_37);
@ -241,23 +251,23 @@ fn main() -> () {
unreachable; unreachable;
} }
bb17: {
goto -> bb19;
}
bb18: {
_22 = const ();
goto -> bb19;
}
bb19: { bb19: {
StorageDead(_30); goto -> bb21;
StorageDead(_29);
StorageDead(_28);
goto -> bb20;
} }
bb20: { bb20: {
_22 = const ();
goto -> bb21;
}
bb21: {
StorageDead(_30);
StorageDead(_29);
StorageDead(_28);
goto -> bb22;
}
bb22: {
StorageDead(_27); StorageDead(_27);
StorageDead(_25); StorageDead(_25);
StorageDead(_23); StorageDead(_23);
@ -266,7 +276,7 @@ fn main() -> () {
return; return;
} }
bb21 (cleanup): { bb23 (cleanup): {
resume; resume;
} }
} }

View file

@ -67,7 +67,7 @@ fn main() -> () {
StorageLive(_2); StorageLive(_2);
StorageLive(_3); StorageLive(_3);
StorageLive(_4); StorageLive(_4);
_4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb21]; _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb23];
} }
bb1: { bb1: {
@ -91,24 +91,29 @@ fn main() -> () {
_11 = &(*_8); _11 = &(*_8);
StorageLive(_12); StorageLive(_12);
_12 = &(*_9); _12 = &(*_9);
_10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb2, unwind: bb21]; _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb3, unwind: bb23];
} }
bb2: { bb2: {
switchInt(move _10) -> [0: bb4, otherwise: bb3]; FakeRead(ForMatchedPlace(None), _2);
unreachable;
} }
bb3: { bb3: {
StorageDead(_12); switchInt(move _10) -> [0: bb5, otherwise: bb4];
StorageDead(_11);
goto -> bb8;
} }
bb4: { bb4: {
goto -> bb5; StorageDead(_12);
StorageDead(_11);
goto -> bb9;
} }
bb5: { bb5: {
goto -> bb6;
}
bb6: {
StorageDead(_12); StorageDead(_12);
StorageDead(_11); StorageDead(_11);
StorageLive(_14); StorageLive(_14);
@ -127,10 +132,10 @@ fn main() -> () {
_19 = &(*_20); _19 = &(*_20);
StorageLive(_21); StorageLive(_21);
_21 = Option::<Arguments<'_>>::None; _21 = Option::<Arguments<'_>>::None;
_15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb21; _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb23;
} }
bb6: { bb7: {
StorageDead(_21); StorageDead(_21);
StorageDead(_19); StorageDead(_19);
StorageDead(_17); StorageDead(_17);
@ -142,23 +147,23 @@ fn main() -> () {
unreachable; unreachable;
} }
bb7: {
goto -> bb9;
}
bb8: { bb8: {
_1 = const (); goto -> bb10;
goto -> bb9;
} }
bb9: { bb9: {
StorageDead(_10); _1 = const ();
StorageDead(_9);
StorageDead(_8);
goto -> bb10; goto -> bb10;
} }
bb10: { bb10: {
StorageDead(_10);
StorageDead(_9);
StorageDead(_8);
goto -> bb11;
}
bb11: {
StorageDead(_7); StorageDead(_7);
StorageDead(_6); StorageDead(_6);
StorageDead(_4); StorageDead(_4);
@ -168,10 +173,10 @@ fn main() -> () {
StorageLive(_23); StorageLive(_23);
StorageLive(_24); StorageLive(_24);
StorageLive(_25); StorageLive(_25);
_25 = function_with_bytes::<&*b"AAAA">() -> [return: bb11, unwind: bb21]; _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb12, unwind: bb23];
} }
bb11: { bb12: {
_24 = &_25; _24 = &_25;
StorageLive(_26); StorageLive(_26);
StorageLive(_27); StorageLive(_27);
@ -190,24 +195,29 @@ fn main() -> () {
_31 = &(*_28); _31 = &(*_28);
StorageLive(_32); StorageLive(_32);
_32 = &(*_29); _32 = &(*_29);
_30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb12, unwind: bb21]; _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb14, unwind: bb23];
}
bb12: {
switchInt(move _30) -> [0: bb14, otherwise: bb13];
} }
bb13: { bb13: {
StorageDead(_32); FakeRead(ForMatchedPlace(None), _23);
StorageDead(_31); unreachable;
goto -> bb18;
} }
bb14: { bb14: {
goto -> bb15; switchInt(move _30) -> [0: bb16, otherwise: bb15];
} }
bb15: { bb15: {
StorageDead(_32);
StorageDead(_31);
goto -> bb20;
}
bb16: {
goto -> bb17;
}
bb17: {
StorageDead(_32); StorageDead(_32);
StorageDead(_31); StorageDead(_31);
StorageLive(_34); StorageLive(_34);
@ -226,10 +236,10 @@ fn main() -> () {
_39 = &(*_40); _39 = &(*_40);
StorageLive(_41); StorageLive(_41);
_41 = Option::<Arguments<'_>>::None; _41 = Option::<Arguments<'_>>::None;
_35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb21; _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb23;
} }
bb16: { bb18: {
StorageDead(_41); StorageDead(_41);
StorageDead(_39); StorageDead(_39);
StorageDead(_37); StorageDead(_37);
@ -241,23 +251,23 @@ fn main() -> () {
unreachable; unreachable;
} }
bb17: {
goto -> bb19;
}
bb18: {
_22 = const ();
goto -> bb19;
}
bb19: { bb19: {
StorageDead(_30); goto -> bb21;
StorageDead(_29);
StorageDead(_28);
goto -> bb20;
} }
bb20: { bb20: {
_22 = const ();
goto -> bb21;
}
bb21: {
StorageDead(_30);
StorageDead(_29);
StorageDead(_28);
goto -> bb22;
}
bb22: {
StorageDead(_27); StorageDead(_27);
StorageDead(_25); StorageDead(_25);
StorageDead(_23); StorageDead(_23);
@ -266,7 +276,7 @@ fn main() -> () {
return; return;
} }
bb21 (cleanup): { bb23 (cleanup): {
resume; resume;
} }
} }

View file

@ -24,20 +24,20 @@
bb1: { bb1: {
_4 = discriminant(_1); _4 = discriminant(_1);
switchInt(move _4) -> [0: bb4, 1: bb5, 2: bb6, 3: bb2, otherwise: bb3]; switchInt(move _4) -> [0: bb4, 1: bb5, 2: bb6, 3: bb3, otherwise: bb2];
} }
bb2: { bb2: {
unreachable;
}
bb3: {
_0 = const (); _0 = const ();
StorageDead(_2); StorageDead(_2);
StorageDead(_1); StorageDead(_1);
return; return;
} }
bb3: {
unreachable;
}
bb4: { bb4: {
StorageLive(_5); StorageLive(_5);
_5 = DFA::B; _5 = DFA::B;

View file

@ -24,20 +24,20 @@
bb1: { bb1: {
_4 = discriminant(_1); _4 = discriminant(_1);
switchInt(move _4) -> [0: bb4, 1: bb5, 2: bb6, 3: bb2, otherwise: bb3]; switchInt(move _4) -> [0: bb4, 1: bb5, 2: bb6, 3: bb3, otherwise: bb2];
} }
bb2: { bb2: {
unreachable;
}
bb3: {
_0 = const (); _0 = const ();
StorageDead(_2); StorageDead(_2);
StorageDead(_1); StorageDead(_1);
return; return;
} }
bb3: {
unreachable;
}
bb4: { bb4: {
StorageLive(_5); StorageLive(_5);
_5 = DFA::B; _5 = DFA::B;

View file

@ -56,10 +56,14 @@
StorageLive(_11); StorageLive(_11);
StorageLive(_12); StorageLive(_12);
_10 = discriminant(_4); _10 = discriminant(_4);
switchInt(move _10) -> [0: bb7, 1: bb6, otherwise: bb2]; switchInt(move _10) -> [0: bb7, 1: bb6, otherwise: bb1];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_9); StorageLive(_9);
_9 = ((_3 as Continue).0: i32); _9 = ((_3 as Continue).0: i32);
_2 = _9; _2 = _9;
@ -70,10 +74,6 @@
goto -> bb4; goto -> bb4;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
StorageLive(_6); StorageLive(_6);
_6 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); _6 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>);
@ -103,8 +103,8 @@
StorageDead(_10); StorageDead(_10);
StorageDead(_4); StorageDead(_4);
_5 = discriminant(_3); _5 = discriminant(_3);
- switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; - switchInt(move _5) -> [0: bb2, 1: bb3, otherwise: bb1];
+ goto -> bb1; + goto -> bb2;
} }
bb6: { bb6: {

View file

@ -56,10 +56,14 @@
StorageLive(_11); StorageLive(_11);
StorageLive(_12); StorageLive(_12);
_10 = discriminant(_4); _10 = discriminant(_4);
switchInt(move _10) -> [0: bb7, 1: bb6, otherwise: bb2]; switchInt(move _10) -> [0: bb7, 1: bb6, otherwise: bb1];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_9); StorageLive(_9);
_9 = ((_3 as Continue).0: i32); _9 = ((_3 as Continue).0: i32);
_2 = _9; _2 = _9;
@ -70,10 +74,6 @@
goto -> bb4; goto -> bb4;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
StorageLive(_6); StorageLive(_6);
_6 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); _6 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>);
@ -103,8 +103,8 @@
StorageDead(_10); StorageDead(_10);
StorageDead(_4); StorageDead(_4);
_5 = discriminant(_3); _5 = discriminant(_3);
- switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; - switchInt(move _5) -> [0: bb2, 1: bb3, otherwise: bb1];
+ goto -> bb1; + goto -> bb2;
} }
bb6: { bb6: {

View file

@ -12,12 +12,12 @@ use std::ops::ControlFlow;
fn too_complex(x: Result<i32, usize>) -> Option<i32> { fn too_complex(x: Result<i32, usize>) -> Option<i32> {
// CHECK-LABEL: fn too_complex( // CHECK-LABEL: fn too_complex(
// CHECK: bb0: { // CHECK: bb0: {
// CHECK: switchInt(move {{_.*}}) -> [0: bb3, 1: bb1, otherwise: bb2]; // CHECK: switchInt(move {{_.*}}) -> [0: bb3, 1: bb2, otherwise: bb1];
// CHECK: bb1: { // CHECK: bb1: {
// CHECK: unreachable;
// CHECK: bb2: {
// CHECK: [[controlflow:_.*]] = ControlFlow::<usize, i32>::Break( // CHECK: [[controlflow:_.*]] = ControlFlow::<usize, i32>::Break(
// CHECK: goto -> bb8; // CHECK: goto -> bb8;
// CHECK: bb2: {
// CHECK: unreachable;
// CHECK: bb3: { // CHECK: bb3: {
// CHECK: [[controlflow]] = ControlFlow::<usize, i32>::Continue( // CHECK: [[controlflow]] = ControlFlow::<usize, i32>::Continue(
// CHECK: goto -> bb4; // CHECK: goto -> bb4;
@ -50,13 +50,13 @@ fn identity(x: Result<i32, i32>) -> Result<i32, i32> {
// CHECK-LABEL: fn identity( // CHECK-LABEL: fn identity(
// CHECK: bb0: { // CHECK: bb0: {
// CHECK: [[x:_.*]] = _1; // CHECK: [[x:_.*]] = _1;
// CHECK: switchInt(move {{_.*}}) -> [0: bb7, 1: bb6, otherwise: bb2]; // CHECK: switchInt(move {{_.*}}) -> [0: bb7, 1: bb6, otherwise: bb1];
// CHECK: bb1: { // CHECK: bb1: {
// CHECK: unreachable;
// CHECK: bb2: {
// CHECK: {{_.*}} = (([[controlflow:_.*]] as Continue).0: i32); // CHECK: {{_.*}} = (([[controlflow:_.*]] as Continue).0: i32);
// CHECK: _0 = Result::<i32, i32>::Ok( // CHECK: _0 = Result::<i32, i32>::Ok(
// CHECK: goto -> bb4; // CHECK: goto -> bb4;
// CHECK: bb2: {
// CHECK: unreachable;
// CHECK: bb3: { // CHECK: bb3: {
// CHECK: {{_.*}} = (([[controlflow]] as Break).0: std::result::Result<std::convert::Infallible, i32>); // CHECK: {{_.*}} = (([[controlflow]] as Break).0: std::result::Result<std::convert::Infallible, i32>);
// CHECK: _0 = Result::<i32, i32>::Err( // CHECK: _0 = Result::<i32, i32>::Err(
@ -64,7 +64,7 @@ fn identity(x: Result<i32, i32>) -> Result<i32, i32> {
// CHECK: bb4: { // CHECK: bb4: {
// CHECK: return; // CHECK: return;
// CHECK: bb5: { // CHECK: bb5: {
// CHECK: goto -> bb1; // CHECK: goto -> bb2;
// CHECK: bb6: { // CHECK: bb6: {
// CHECK: {{_.*}} = move (([[x]] as Err).0: i32); // CHECK: {{_.*}} = move (([[x]] as Err).0: i32);
// CHECK: [[controlflow]] = ControlFlow::<Result<Infallible, i32>, i32>::Break( // CHECK: [[controlflow]] = ControlFlow::<Result<Infallible, i32>, i32>::Break(
@ -93,11 +93,11 @@ fn dfa() {
// CHECK: {{_.*}} = DFA::A; // CHECK: {{_.*}} = DFA::A;
// CHECK: goto -> bb1; // CHECK: goto -> bb1;
// CHECK: bb1: { // CHECK: bb1: {
// CHECK: switchInt({{.*}}) -> [0: bb4, 1: bb5, 2: bb6, 3: bb2, otherwise: bb3]; // CHECK: switchInt({{.*}}) -> [0: bb4, 1: bb5, 2: bb6, 3: bb3, otherwise: bb2];
// CHECK: bb2: { // CHECK: bb2: {
// CHECK: return;
// CHECK: bb3: {
// CHECK: unreachable; // CHECK: unreachable;
// CHECK: bb3: {
// CHECK: return;
// CHECK: bb4: { // CHECK: bb4: {
// CHECK: {{_.*}} = DFA::B; // CHECK: {{_.*}} = DFA::B;
// CHECK: goto -> bb1; // CHECK: goto -> bb1;

View file

@ -30,10 +30,14 @@
bb0: { bb0: {
StorageLive(_2); StorageLive(_2);
_3 = discriminant(_1); _3 = discriminant(_1);
switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_6); StorageLive(_6);
_6 = ((_1 as Err).0: usize); _6 = ((_1 as Err).0: usize);
StorageLive(_7); StorageLive(_7);
@ -45,10 +49,6 @@
+ goto -> bb8; + goto -> bb8;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
StorageLive(_4); StorageLive(_4);
_4 = ((_1 as Ok).0: i32); _4 = ((_1 as Ok).0: i32);
@ -62,7 +62,7 @@
bb4: { bb4: {
_8 = discriminant(_2); _8 = discriminant(_2);
- switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb2]; - switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb1];
+ goto -> bb6; + goto -> bb6;
} }

View file

@ -30,10 +30,14 @@
bb0: { bb0: {
StorageLive(_2); StorageLive(_2);
_3 = discriminant(_1); _3 = discriminant(_1);
switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; switchInt(move _3) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_6); StorageLive(_6);
_6 = ((_1 as Err).0: usize); _6 = ((_1 as Err).0: usize);
StorageLive(_7); StorageLive(_7);
@ -45,10 +49,6 @@
+ goto -> bb8; + goto -> bb8;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
StorageLive(_4); StorageLive(_4);
_4 = ((_1 as Ok).0: i32); _4 = ((_1 as Ok).0: i32);
@ -62,7 +62,7 @@
bb4: { bb4: {
_8 = discriminant(_2); _8 = discriminant(_2);
- switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb2]; - switchInt(move _8) -> [0: bb6, 1: bb5, otherwise: bb1];
+ goto -> bb6; + goto -> bb6;
} }

View file

@ -32,33 +32,25 @@
bb0: { bb0: {
PlaceMention(_2); PlaceMention(_2);
- switchInt((_2.0: bool)) -> [0: bb1, otherwise: bb2]; - switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb1];
+ switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1]; + switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1];
} }
bb1: { bb1: {
- falseEdge -> [real: bb8, imaginary: bb3]; - switchInt((_2.1: bool)) -> [0: bb5, otherwise: bb2];
+ switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2]; + switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2];
} }
bb2: { bb2: {
- switchInt((_2.1: bool)) -> [0: bb3, otherwise: bb4]; - switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17]; + switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
} }
bb3: { bb3: {
- falseEdge -> [real: bb13, imaginary: bb5]; - falseEdge -> [real: bb20, imaginary: bb4];
- } - }
- -
- bb4: { - bb4: {
- switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb5];
- }
-
- bb5: {
- falseEdge -> [real: bb20, imaginary: bb6];
- }
-
- bb6: {
StorageLive(_15); StorageLive(_15);
_15 = (_2.1: bool); _15 = (_2.1: bool);
StorageLive(_16); StorageLive(_16);
@ -67,6 +59,14 @@
+ goto -> bb16; + goto -> bb16;
} }
- bb5: {
- falseEdge -> [real: bb13, imaginary: bb3];
- }
-
- bb6: {
- falseEdge -> [real: bb8, imaginary: bb5];
- }
-
- bb7: { - bb7: {
+ bb4: { + bb4: {
_0 = const 1_i32; _0 = const 1_i32;
@ -127,7 +127,7 @@
StorageDead(_9); StorageDead(_9);
StorageDead(_8); StorageDead(_8);
StorageDead(_6); StorageDead(_6);
- falseEdge -> [real: bb2, imaginary: bb3]; - falseEdge -> [real: bb1, imaginary: bb5];
+ goto -> bb1; + goto -> bb1;
} }
@ -184,7 +184,7 @@
StorageDead(_12); StorageDead(_12);
StorageDead(_8); StorageDead(_8);
StorageDead(_6); StorageDead(_6);
- falseEdge -> [real: bb4, imaginary: bb5]; - falseEdge -> [real: bb2, imaginary: bb3];
+ goto -> bb2; + goto -> bb2;
} }

View file

@ -32,33 +32,25 @@
bb0: { bb0: {
PlaceMention(_2); PlaceMention(_2);
- switchInt((_2.0: bool)) -> [0: bb1, otherwise: bb2]; - switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb1];
+ switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1]; + switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1];
} }
bb1: { bb1: {
- falseEdge -> [real: bb8, imaginary: bb3]; - switchInt((_2.1: bool)) -> [0: bb5, otherwise: bb2];
+ switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2]; + switchInt((_2.1: bool)) -> [0: bb10, otherwise: bb2];
} }
bb2: { bb2: {
- switchInt((_2.1: bool)) -> [0: bb3, otherwise: bb4]; - switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17]; + switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
} }
bb3: { bb3: {
- falseEdge -> [real: bb13, imaginary: bb5]; - falseEdge -> [real: bb20, imaginary: bb4];
- } - }
- -
- bb4: { - bb4: {
- switchInt((_2.0: bool)) -> [0: bb6, otherwise: bb5];
- }
-
- bb5: {
- falseEdge -> [real: bb20, imaginary: bb6];
- }
-
- bb6: {
StorageLive(_15); StorageLive(_15);
_15 = (_2.1: bool); _15 = (_2.1: bool);
StorageLive(_16); StorageLive(_16);
@ -67,6 +59,14 @@
+ goto -> bb16; + goto -> bb16;
} }
- bb5: {
- falseEdge -> [real: bb13, imaginary: bb3];
- }
-
- bb6: {
- falseEdge -> [real: bb8, imaginary: bb5];
- }
-
- bb7: { - bb7: {
+ bb4: { + bb4: {
_0 = const 1_i32; _0 = const 1_i32;
@ -127,7 +127,7 @@
StorageDead(_9); StorageDead(_9);
StorageDead(_8); StorageDead(_8);
StorageDead(_6); StorageDead(_6);
- falseEdge -> [real: bb2, imaginary: bb3]; - falseEdge -> [real: bb1, imaginary: bb5];
+ goto -> bb1; + goto -> bb1;
} }
@ -184,7 +184,7 @@
StorageDead(_12); StorageDead(_12);
StorageDead(_8); StorageDead(_8);
StorageDead(_6); StorageDead(_6);
- falseEdge -> [real: bb4, imaginary: bb5]; - falseEdge -> [real: bb2, imaginary: bb3];
+ goto -> bb2; + goto -> bb2;
} }

View file

@ -32,12 +32,12 @@ fn main() -> () {
} }
bb1: { bb1: {
falseEdge -> [real: bb9, imaginary: bb4]; _3 = const 3_i32;
goto -> bb14;
} }
bb2: { bb2: {
_3 = const 3_i32; falseEdge -> [real: bb9, imaginary: bb4];
goto -> bb14;
} }
bb3: { bb3: {
@ -50,11 +50,11 @@ fn main() -> () {
} }
bb5: { bb5: {
switchInt(_1) -> [4294967295: bb6, otherwise: bb2]; switchInt(_1) -> [4294967295: bb6, otherwise: bb1];
} }
bb6: { bb6: {
falseEdge -> [real: bb13, imaginary: bb2]; falseEdge -> [real: bb13, imaginary: bb1];
} }
bb7: { bb7: {
@ -64,7 +64,7 @@ fn main() -> () {
bb8: { bb8: {
_7 = Lt(_1, const 10_i32); _7 = Lt(_1, const 10_i32);
switchInt(move _7) -> [0: bb3, otherwise: bb1]; switchInt(move _7) -> [0: bb3, otherwise: bb2];
} }
bb9: { bb9: {
@ -83,7 +83,7 @@ fn main() -> () {
bb11: { bb11: {
StorageDead(_9); StorageDead(_9);
falseEdge -> [real: bb2, imaginary: bb4]; falseEdge -> [real: bb1, imaginary: bb4];
} }
bb12: { bb12: {

View file

@ -8,16 +8,16 @@
bb0: { bb0: {
_2 = discriminant(_1); _2 = discriminant(_1);
switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
_0 = const 1_u8; unreachable;
goto -> bb4;
} }
bb2: { bb2: {
unreachable; _0 = const 1_u8;
goto -> bb4;
} }
bb3: { bb3: {

View file

@ -8,16 +8,16 @@
bb0: { bb0: {
_2 = discriminant(_1); _2 = discriminant(_1);
switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
_0 = const 1_i8; unreachable;
goto -> bb4;
} }
bb2: { bb2: {
unreachable; _0 = const 1_i8;
goto -> bb4;
} }
bb3: { bb3: {

View file

@ -15,16 +15,16 @@ fn unwrap(_1: Option<T>) -> T {
bb0: { bb0: {
_2 = discriminant(_1); _2 = discriminant(_1);
switchInt(move _2) -> [0: bb1, 1: bb3, otherwise: bb2]; switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1];
} }
bb1: { bb1: {
StorageLive(_4); unreachable;
_4 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable;
} }
bb2: { bb2: {
unreachable; StorageLive(_4);
_4 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable;
} }
bb3: { bb3: {

View file

@ -15,16 +15,16 @@ fn unwrap(_1: Option<T>) -> T {
bb0: { bb0: {
_2 = discriminant(_1); _2 = discriminant(_1);
switchInt(move _2) -> [0: bb1, 1: bb3, otherwise: bb2]; switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1];
} }
bb1: { bb1: {
StorageLive(_4); unreachable;
_4 = begin_panic::<&str>(const "explicit panic") -> bb4;
} }
bb2: { bb2: {
unreachable; StorageLive(_4);
_4 = begin_panic::<&str>(const "explicit panic") -> bb4;
} }
bb3: { bb3: {

View file

@ -67,10 +67,14 @@
StorageLive(_7); StorageLive(_7);
_7 = Option::<i32>::Some(const 0_i32); _7 = Option::<i32>::Some(const 0_i32);
_8 = discriminant(_7); _8 = discriminant(_7);
switchInt(move _8) -> [0: bb3, 1: bb1, otherwise: bb2]; switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_9); StorageLive(_9);
_27 = const _; _27 = const _;
_9 = &(((*_27) as Some).0: i32); _9 = &(((*_27) as Some).0: i32);
@ -79,10 +83,6 @@
goto -> bb4; goto -> bb4;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
- _6 = const (); - _6 = const ();
goto -> bb4; goto -> bb4;

View file

@ -55,10 +55,14 @@
bb3: { bb3: {
- StorageDead(_8); - StorageDead(_8);
_10 = discriminant(_7); _10 = discriminant(_7);
switchInt(move _10) -> [0: bb6, 1: bb4, otherwise: bb5]; switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb4];
} }
bb4: { bb4: {
unreachable;
}
bb5: {
- StorageLive(_12); - StorageLive(_12);
_12 = ((_7 as Some).0: i32); _12 = ((_7 as Some).0: i32);
- StorageLive(_13); - StorageLive(_13);
@ -74,10 +78,6 @@
goto -> bb2; goto -> bb2;
} }
bb5: {
unreachable;
}
bb6: { bb6: {
_0 = const (); _0 = const ();
- StorageDead(_9); - StorageDead(_9);

View file

@ -55,10 +55,14 @@
bb3: { bb3: {
- StorageDead(_8); - StorageDead(_8);
_10 = discriminant(_7); _10 = discriminant(_7);
switchInt(move _10) -> [0: bb6, 1: bb4, otherwise: bb5]; switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb4];
} }
bb4: { bb4: {
unreachable;
}
bb5: {
- StorageLive(_12); - StorageLive(_12);
_12 = ((_7 as Some).0: i32); _12 = ((_7 as Some).0: i32);
- StorageLive(_13); - StorageLive(_13);
@ -74,10 +78,6 @@
goto -> bb2; goto -> bb2;
} }
bb5: {
unreachable;
}
bb6: { bb6: {
_0 = const (); _0 = const ();
- StorageDead(_9); - StorageDead(_9);

View file

@ -18,10 +18,14 @@
- _5 = const false; - _5 = const false;
- _5 = const true; - _5 = const true;
_2 = discriminant(_1); _2 = discriminant(_1);
switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_3); StorageLive(_3);
_3 = move ((_1 as Some).0: std::boxed::Box<()>); _3 = move ((_1 as Some).0: std::boxed::Box<()>);
StorageLive(_4); StorageLive(_4);
@ -32,10 +36,6 @@
goto -> bb4; goto -> bb4;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
_0 = Option::<Box<()>>::None; _0 = Option::<Box<()>>::None;
goto -> bb4; goto -> bb4;

View file

@ -30,11 +30,15 @@
StorageLive(_4); StorageLive(_4);
_4 = &(_1.1: Test3); _4 = &(_1.1: Test3);
_5 = discriminant((*_4)); _5 = discriminant((*_4));
- switchInt(move _5) -> [0: bb3, 1: bb4, 2: bb5, 3: bb1, otherwise: bb2]; - switchInt(move _5) -> [0: bb3, 1: bb4, 2: bb5, 3: bb2, otherwise: bb1];
+ switchInt(move _5) -> [0: bb12, 1: bb12, 2: bb5, 3: bb1, otherwise: bb12]; + switchInt(move _5) -> [0: bb12, 1: bb12, 2: bb5, 3: bb2, otherwise: bb12];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_8); StorageLive(_8);
_8 = const "D"; _8 = const "D";
_3 = &(*_8); _3 = &(*_8);
@ -42,10 +46,6 @@
goto -> bb6; goto -> bb6;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
_3 = const "A(Empty)"; _3 = const "A(Empty)";
goto -> bb6; goto -> bb6;
@ -72,7 +72,7 @@
StorageDead(_3); StorageDead(_3);
StorageLive(_9); StorageLive(_9);
_10 = discriminant((_1.1: Test3)); _10 = discriminant((_1.1: Test3));
- switchInt(move _10) -> [0: bb8, 1: bb9, 2: bb10, 3: bb7, otherwise: bb2]; - switchInt(move _10) -> [0: bb8, 1: bb9, 2: bb10, 3: bb7, otherwise: bb1];
+ switchInt(move _10) -> [0: bb12, 1: bb12, 2: bb10, 3: bb7, otherwise: bb12]; + switchInt(move _10) -> [0: bb12, 1: bb12, 2: bb10, 3: bb7, otherwise: bb12];
} }

View file

@ -13,11 +13,15 @@
StorageLive(_2); StorageLive(_2);
_2 = Test2::D; _2 = Test2::D;
_3 = discriminant(_2); _3 = discriminant(_2);
- switchInt(move _3) -> [4: bb3, 5: bb1, otherwise: bb2]; - switchInt(move _3) -> [4: bb3, 5: bb2, otherwise: bb1];
+ switchInt(move _3) -> [4: bb3, 5: bb1, otherwise: bb5]; + switchInt(move _3) -> [4: bb3, 5: bb2, otherwise: bb5];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_4); StorageLive(_4);
_4 = const "E"; _4 = const "E";
_1 = &(*_4); _1 = &(*_4);
@ -25,10 +29,6 @@
goto -> bb4; goto -> bb4;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
_1 = const "D"; _1 = const "D";
goto -> bb4; goto -> bb4;

View file

@ -32,7 +32,7 @@ struct Plop {
fn simple() { fn simple() {
// CHECK-LABEL: fn simple( // CHECK-LABEL: fn simple(
// CHECK: [[discr:_.*]] = discriminant( // CHECK: [[discr:_.*]] = discriminant(
// CHECK: switchInt(move [[discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: bb1, otherwise: [[unreachable]]]; // CHECK: switchInt(move [[discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: bb2, otherwise: [[unreachable]]];
// CHECK: [[unreachable]]: { // CHECK: [[unreachable]]: {
// CHECK-NEXT: unreachable; // CHECK-NEXT: unreachable;
match Test1::C { match Test1::C {
@ -46,7 +46,7 @@ fn simple() {
fn custom_discriminant() { fn custom_discriminant() {
// CHECK-LABEL: fn custom_discriminant( // CHECK-LABEL: fn custom_discriminant(
// CHECK: [[discr:_.*]] = discriminant( // CHECK: [[discr:_.*]] = discriminant(
// CHECK: switchInt(move [[discr]]) -> [4: bb3, 5: bb1, otherwise: bb5]; // CHECK: switchInt(move [[discr]]) -> [4: bb3, 5: bb2, otherwise: bb5];
// CHECK: bb5: { // CHECK: bb5: {
// CHECK-NEXT: unreachable; // CHECK-NEXT: unreachable;
match Test2::D { match Test2::D {
@ -61,7 +61,7 @@ fn byref() {
let plop = Plop { xx: 51, test3: Test3::C }; let plop = Plop { xx: 51, test3: Test3::C };
// CHECK: [[ref_discr:_.*]] = discriminant((* // CHECK: [[ref_discr:_.*]] = discriminant((*
// CHECK: switchInt(move [[ref_discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: bb5, 3: bb1, otherwise: [[unreachable]]]; // CHECK: switchInt(move [[ref_discr]]) -> [0: [[unreachable:bb.*]], 1: [[unreachable]], 2: bb5, 3: bb2, otherwise: [[unreachable]]];
match &plop.test3 { match &plop.test3 {
Test3::A(_) => "A(Empty)", Test3::A(_) => "A(Empty)",
Test3::B(_) => "B(Empty)", Test3::B(_) => "B(Empty)",

View file

@ -14,11 +14,15 @@
StorageLive(_2); StorageLive(_2);
_2 = Test1::C; _2 = Test1::C;
_3 = discriminant(_2); _3 = discriminant(_2);
- switchInt(move _3) -> [0: bb3, 1: bb4, 2: bb1, otherwise: bb2]; - switchInt(move _3) -> [0: bb3, 1: bb4, 2: bb2, otherwise: bb1];
+ switchInt(move _3) -> [0: bb6, 1: bb6, 2: bb1, otherwise: bb6]; + switchInt(move _3) -> [0: bb6, 1: bb6, 2: bb2, otherwise: bb6];
} }
bb1: { bb1: {
unreachable;
}
bb2: {
StorageLive(_5); StorageLive(_5);
_5 = const "C"; _5 = const "C";
_1 = &(*_5); _1 = &(*_5);
@ -26,10 +30,6 @@
goto -> bb5; goto -> bb5;
} }
bb2: {
unreachable;
}
bb3: { bb3: {
_1 = const "A(Empty)"; _1 = const "A(Empty)";
goto -> bb5; goto -> bb5;

View file

@ -19,20 +19,20 @@
bb1: { bb1: {
_2 = discriminant(_1); _2 = discriminant(_1);
- switchInt(move _2) -> [0: bb4, 1: bb2, otherwise: bb3]; - switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb2];
+ _5 = Eq(_2, const 0_isize); + _5 = Eq(_2, const 0_isize);
+ assume(move _5); + assume(move _5);
+ goto -> bb4; + goto -> bb4;
} }
bb2: { bb2: {
- StorageLive(_3);
- _3 = move ((_1 as Some).0: Empty);
- StorageLive(_4);
unreachable; unreachable;
} }
bb3: { bb3: {
- StorageLive(_3);
- _3 = move ((_1 as Some).0: Empty);
- StorageLive(_4);
unreachable; unreachable;
} }

View file

@ -19,20 +19,20 @@
bb1: { bb1: {
_2 = discriminant(_1); _2 = discriminant(_1);
- switchInt(move _2) -> [0: bb4, 1: bb2, otherwise: bb3]; - switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb2];
+ _5 = Eq(_2, const 0_isize); + _5 = Eq(_2, const 0_isize);
+ assume(move _5); + assume(move _5);
+ goto -> bb4; + goto -> bb4;
} }
bb2: { bb2: {
- StorageLive(_3);
- _3 = move ((_1 as Some).0: Empty);
- StorageLive(_4);
unreachable; unreachable;
} }
bb3: { bb3: {
- StorageLive(_3);
- _3 = move ((_1 as Some).0: Empty);
- StorageLive(_4);
unreachable; unreachable;
} }

View file

@ -0,0 +1,29 @@
// This test ensures that non-glob reexports don't get their attributes merge with
// the reexported item whereas glob reexports do with the `doc_auto_cfg` feature.
#![crate_name = "foo"]
#![feature(doc_auto_cfg)]
// @has 'foo/index.html'
// There are two items.
// @count - '//*[@class="item-table"]//div[@class="item-name"]' 2
// Only one of them should have an attribute.
// @count - '//*[@class="item-table"]//div[@class="item-name"]/*[@class="stab portability"]' 1
mod a {
#[cfg(not(feature = "a"))]
pub struct Test1;
}
mod b {
#[cfg(not(feature = "a"))]
pub struct Test2;
}
// @has 'foo/struct.Test1.html'
// @count - '//*[@id="main-content"]/*[@class="item-info"]' 1
// @has - '//*[@id="main-content"]/*[@class="item-info"]' 'Available on non-crate feature a only.'
pub use a::*;
// @has 'foo/struct.Test2.html'
// @count - '//*[@id="main-content"]/*[@class="item-info"]' 0
pub use b::Test2;

View file

@ -0,0 +1,23 @@
error[E0282]: type annotations needed
--> $DIR/recursive-coroutine-boxed.rs:10:23
|
LL | let mut gen = Box::pin(foo());
| ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box`
...
LL | let mut r = gen.as_mut().resume(());
| ------ type must be known at this point
|
help: consider specifying the generic argument
|
LL | let mut gen = Box::<T>::pin(foo());
| +++++
error[E0282]: type annotations needed
--> $DIR/recursive-coroutine-boxed.rs:10:32
|
LL | let mut gen = Box::pin(foo());
| ^^^^^ cannot infer type for opaque type `impl Coroutine<Yield = (), Return = ()>`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0282`.

View file

@ -1,5 +1,5 @@
// check-pass
// revisions: current next // revisions: current next
//[current] check-pass
//[next] compile-flags: -Znext-solver //[next] compile-flags: -Znext-solver
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait)]
@ -8,6 +8,8 @@ use std::ops::{Coroutine, CoroutineState};
fn foo() -> impl Coroutine<Yield = (), Return = ()> { fn foo() -> impl Coroutine<Yield = (), Return = ()> {
|| { || {
let mut gen = Box::pin(foo()); let mut gen = Box::pin(foo());
//[next]~^ ERROR type annotations needed
//[next]~| ERROR type annotations needed
let mut r = gen.as_mut().resume(()); let mut r = gen.as_mut().resume(());
while let CoroutineState::Yielded(v) = r { while let CoroutineState::Yielded(v) = r {
yield v; yield v;

View file

@ -1,8 +1,8 @@
error[E0284]: type annotations needed: cannot satisfy `A <: B` error[E0284]: type annotations needed: cannot satisfy `A == B`
--> $DIR/two_tait_defining_each_other2.rs:11:5 --> $DIR/two_tait_defining_each_other2.rs:11:5
| |
LL | x // B's hidden type is A (opaquely) LL | x // B's hidden type is A (opaquely)
| ^ cannot satisfy `A <: B` | ^ cannot satisfy `A == B`
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -10,7 +10,7 @@ trait Foo {}
fn muh(x: A) -> B { fn muh(x: A) -> B {
x // B's hidden type is A (opaquely) x // B's hidden type is A (opaquely)
//[current]~^ ERROR opaque type's hidden type cannot be another opaque type //[current]~^ ERROR opaque type's hidden type cannot be another opaque type
//[next]~^^ ERROR type annotations needed: cannot satisfy `A <: B` //[next]~^^ ERROR type annotations needed: cannot satisfy `A == B`
} }
struct Bar; struct Bar;

View file

@ -1,9 +1,10 @@
// compile-flags: -Znext-solver // compile-flags: -Znext-solver
// check-pass // FIXME(-Znext-solver): This test is currently broken because the `deduce_closure_signature`
// is unable to look at nested obligations.
trait Foo { trait Foo {
fn test() -> impl Fn(u32) -> u32 { fn test() -> impl Fn(u32) -> u32 {
|x| x.count_ones() |x| x.count_ones()
//~^ ERROR type annotations needed
} }
} }

View file

@ -0,0 +1,14 @@
error[E0282]: type annotations needed
--> $DIR/deduce-closure-signature-after-normalization.rs:6:10
|
LL | |x| x.count_ones()
| ^ - type must be known at this point
|
help: consider giving this closure parameter an explicit type
|
LL | |x: /* Type */| x.count_ones()
| ++++++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0282`.

View file

@ -1,16 +1,9 @@
error[E0283]: type annotations needed: cannot satisfy `Foo: Send` error[E0284]: type annotations needed: cannot satisfy `Foo == _`
--> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18 --> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18
| |
LL | needs_send::<Foo>(); LL | needs_send::<Foo>();
| ^^^ | ^^^ cannot satisfy `Foo == _`
|
= note: cannot satisfy `Foo: Send`
note: required by a bound in `needs_send`
--> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
|
LL | fn needs_send<T: Send>() {}
| ^^^^ required by this bound in `needs_send`
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0283`. For more information about this error, try `rustc --explain E0284`.

View file

@ -1,16 +1,9 @@
error[E0283]: type annotations needed: cannot satisfy `Foo: Send` error[E0284]: type annotations needed: cannot satisfy `Foo == _`
--> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18 --> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18
| |
LL | needs_send::<Foo>(); LL | needs_send::<Foo>();
| ^^^ | ^^^ cannot satisfy `Foo == _`
|
= note: cannot satisfy `Foo: Send`
note: required by a bound in `needs_send`
--> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
|
LL | fn needs_send<T: Send>() {}
| ^^^^ required by this bound in `needs_send`
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0283`. For more information about this error, try `rustc --explain E0284`.

View file

@ -13,7 +13,7 @@ fn needs_send<T: Send>() {}
fn test(_: Foo) { fn test(_: Foo) {
needs_send::<Foo>(); needs_send::<Foo>();
//~^ ERROR type annotations needed: cannot satisfy `Foo: Send` //~^ ERROR type annotations needed: cannot satisfy `Foo == _`
} }
fn defines(_: Foo) { fn defines(_: Foo) {

View file

@ -1,10 +0,0 @@
// compile-flags: -Zeagerly-emit-delayed-bugs
trait Foo {}
fn main() {}
fn f() -> impl Foo {
//~^ ERROR the trait bound `i32: Foo` is not satisfied
1i32
}

Some files were not shown because too many files have changed in this diff Show more