Auto merge of #117228 - matthiaskrgr:rollup-23zzepv, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #116905 (refactor(compiler/resolve): simplify some code) - #117095 (Add way to differentiate argument locals from other locals in Stable MIR) - #117143 (Avoid unbounded O(n^2) when parsing nested type args) - #117194 (Minor improvements to `rustc_incremental`) - #117202 (Revert "Remove TaKO8Ki from reviewers") - #117207 (The value of `-Cinstrument-coverage=` doesn't need to be `Option`) - #117214 (Quietly fail if an error has already occurred) - #117221 (Rename type flag `HAS_TY_GENERATOR` to `HAS_TY_COROUTINE`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8396efecf7
104 changed files with 278 additions and 82 deletions
|
@ -8,7 +8,7 @@ use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_middle::mir::ConstraintCategory;
|
use rustc_middle::mir::ConstraintCategory;
|
||||||
use rustc_middle::traits::query::OutlivesBound;
|
use rustc_middle::traits::query::OutlivesBound;
|
||||||
use rustc_middle::ty::{self, RegionVid, Ty};
|
use rustc_middle::ty::{self, RegionVid, Ty};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use type_op::TypeOpOutput;
|
use type_op::TypeOpOutput;
|
||||||
|
@ -318,7 +318,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
.param_env
|
.param_env
|
||||||
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
|
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
|
||||||
.fully_perform(self.infcx, DUMMY_SP)
|
.fully_perform(self.infcx, DUMMY_SP)
|
||||||
.unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty));
|
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
|
||||||
|
.ok()?;
|
||||||
debug!(?bounds, ?constraints);
|
debug!(?bounds, ?constraints);
|
||||||
self.add_outlives_bounds(bounds);
|
self.add_outlives_bounds(bounds);
|
||||||
constraints
|
constraints
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#![cfg_attr(not(bootstrap), doc(rust_logo))]
|
#![cfg_attr(not(bootstrap), doc(rust_logo))]
|
||||||
#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
|
#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
|
||||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||||
#![feature(never_type)]
|
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
#![deny(rustc::untranslatable_diagnostic)]
|
#![deny(rustc::untranslatable_diagnostic)]
|
||||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||||
|
@ -19,15 +18,11 @@ mod assert_dep_graph;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod persist;
|
mod persist;
|
||||||
|
|
||||||
use assert_dep_graph::assert_dep_graph;
|
|
||||||
pub use persist::copy_cgu_workproduct_to_incr_comp_cache_dir;
|
pub use persist::copy_cgu_workproduct_to_incr_comp_cache_dir;
|
||||||
pub use persist::delete_workproduct_files;
|
|
||||||
pub use persist::finalize_session_directory;
|
pub use persist::finalize_session_directory;
|
||||||
pub use persist::garbage_collect_session_directories;
|
|
||||||
pub use persist::in_incr_comp_dir;
|
pub use persist::in_incr_comp_dir;
|
||||||
pub use persist::in_incr_comp_dir_sess;
|
pub use persist::in_incr_comp_dir_sess;
|
||||||
pub use persist::load_query_result_cache;
|
pub use persist::load_query_result_cache;
|
||||||
pub use persist::prepare_session_directory;
|
|
||||||
pub use persist::save_dep_graph;
|
pub use persist::save_dep_graph;
|
||||||
pub use persist::save_work_product_index;
|
pub use persist::save_work_product_index;
|
||||||
pub use persist::setup_dep_graph;
|
pub use persist::setup_dep_graph;
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
//! ## Synchronization
|
//! ## Synchronization
|
||||||
//!
|
//!
|
||||||
//! There is some synchronization needed in order for the compiler to be able to
|
//! There is some synchronization needed in order for the compiler to be able to
|
||||||
//! determine whether a given private session directory is not in used any more.
|
//! determine whether a given private session directory is not in use any more.
|
||||||
//! This is done by creating a lock file for each session directory and
|
//! This is done by creating a lock file for each session directory and
|
||||||
//! locking it while the directory is still being used. Since file locks have
|
//! locking it while the directory is still being used. Since file locks have
|
||||||
//! operating system support, we can rely on the lock being released if the
|
//! operating system support, we can rely on the lock being released if the
|
||||||
|
@ -136,26 +136,29 @@ const QUERY_CACHE_FILENAME: &str = "query-cache.bin";
|
||||||
const INT_ENCODE_BASE: usize = base_n::CASE_INSENSITIVE;
|
const INT_ENCODE_BASE: usize = base_n::CASE_INSENSITIVE;
|
||||||
|
|
||||||
/// Returns the path to a session's dependency graph.
|
/// Returns the path to a session's dependency graph.
|
||||||
pub fn dep_graph_path(sess: &Session) -> PathBuf {
|
pub(crate) fn dep_graph_path(sess: &Session) -> PathBuf {
|
||||||
in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME)
|
in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to a session's staging dependency graph.
|
/// Returns the path to a session's staging dependency graph.
|
||||||
///
|
///
|
||||||
/// On the difference between dep-graph and staging dep-graph,
|
/// On the difference between dep-graph and staging dep-graph,
|
||||||
/// see `build_dep_graph`.
|
/// see `build_dep_graph`.
|
||||||
pub fn staging_dep_graph_path(sess: &Session) -> PathBuf {
|
pub(crate) fn staging_dep_graph_path(sess: &Session) -> PathBuf {
|
||||||
in_incr_comp_dir_sess(sess, STAGING_DEP_GRAPH_FILENAME)
|
in_incr_comp_dir_sess(sess, STAGING_DEP_GRAPH_FILENAME)
|
||||||
}
|
}
|
||||||
pub fn work_products_path(sess: &Session) -> PathBuf {
|
|
||||||
|
pub(crate) fn work_products_path(sess: &Session) -> PathBuf {
|
||||||
in_incr_comp_dir_sess(sess, WORK_PRODUCTS_FILENAME)
|
in_incr_comp_dir_sess(sess, WORK_PRODUCTS_FILENAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to a session's query cache.
|
/// Returns the path to a session's query cache.
|
||||||
pub fn query_cache_path(sess: &Session) -> PathBuf {
|
pub fn query_cache_path(sess: &Session) -> PathBuf {
|
||||||
in_incr_comp_dir_sess(sess, QUERY_CACHE_FILENAME)
|
in_incr_comp_dir_sess(sess, QUERY_CACHE_FILENAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Locks a given session directory.
|
/// Locks a given session directory.
|
||||||
pub fn lock_file_path(session_dir: &Path) -> PathBuf {
|
fn lock_file_path(session_dir: &Path) -> PathBuf {
|
||||||
let crate_dir = session_dir.parent().unwrap();
|
let crate_dir = session_dir.parent().unwrap();
|
||||||
|
|
||||||
let directory_name = session_dir.file_name().unwrap().to_string_lossy();
|
let directory_name = session_dir.file_name().unwrap().to_string_lossy();
|
||||||
|
@ -202,7 +205,7 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu
|
||||||
/// The garbage collection will take care of it.
|
/// The garbage collection will take care of it.
|
||||||
///
|
///
|
||||||
/// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph
|
/// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph
|
||||||
pub fn prepare_session_directory(
|
pub(crate) fn prepare_session_directory(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
crate_name: Symbol,
|
crate_name: Symbol,
|
||||||
stable_crate_id: StableCrateId,
|
stable_crate_id: StableCrateId,
|
||||||
|
@ -373,7 +376,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) {
|
||||||
let _ = garbage_collect_session_directories(sess);
|
let _ = garbage_collect_session_directories(sess);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_all_session_dir_contents(sess: &Session) -> io::Result<()> {
|
pub(crate) fn delete_all_session_dir_contents(sess: &Session) -> io::Result<()> {
|
||||||
let sess_dir_iterator = sess.incr_comp_session_dir().read_dir()?;
|
let sess_dir_iterator = sess.incr_comp_session_dir().read_dir()?;
|
||||||
for entry in sess_dir_iterator {
|
for entry in sess_dir_iterator {
|
||||||
let entry = entry?;
|
let entry = entry?;
|
||||||
|
@ -621,7 +624,7 @@ fn is_old_enough_to_be_collected(timestamp: SystemTime) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs garbage collection for the current session.
|
/// Runs garbage collection for the current session.
|
||||||
pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
|
pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
|
||||||
debug!("garbage_collect_session_directories() - begin");
|
debug!("garbage_collect_session_directories() - begin");
|
||||||
|
|
||||||
let session_directory = sess.incr_comp_session_dir();
|
let session_directory = sess.incr_comp_session_dir();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Code to save/load the dep-graph from files.
|
//! Code to load the dep-graph from files.
|
||||||
|
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use rustc_data_structures::memmap::Mmap;
|
use rustc_data_structures::memmap::Mmap;
|
||||||
|
|
|
@ -11,14 +11,11 @@ mod save;
|
||||||
mod work_product;
|
mod work_product;
|
||||||
|
|
||||||
pub use fs::finalize_session_directory;
|
pub use fs::finalize_session_directory;
|
||||||
pub use fs::garbage_collect_session_directories;
|
|
||||||
pub use fs::in_incr_comp_dir;
|
pub use fs::in_incr_comp_dir;
|
||||||
pub use fs::in_incr_comp_dir_sess;
|
pub use fs::in_incr_comp_dir_sess;
|
||||||
pub use fs::prepare_session_directory;
|
|
||||||
pub use load::load_query_result_cache;
|
pub use load::load_query_result_cache;
|
||||||
pub use load::setup_dep_graph;
|
pub use load::setup_dep_graph;
|
||||||
pub use load::LoadResult;
|
pub use load::LoadResult;
|
||||||
pub use save::save_dep_graph;
|
pub use save::save_dep_graph;
|
||||||
pub use save::save_work_product_index;
|
pub use save::save_work_product_index;
|
||||||
pub use work_product::copy_cgu_workproduct_to_incr_comp_cache_dir;
|
pub use work_product::copy_cgu_workproduct_to_incr_comp_cache_dir;
|
||||||
pub use work_product::delete_workproduct_files;
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::assert_dep_graph::assert_dep_graph;
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_data_structures::sync::join;
|
use rustc_data_structures::sync::join;
|
||||||
|
@ -39,7 +40,7 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
|
||||||
let dep_graph_path = dep_graph_path(sess);
|
let dep_graph_path = dep_graph_path(sess);
|
||||||
let staging_dep_graph_path = staging_dep_graph_path(sess);
|
let staging_dep_graph_path = staging_dep_graph_path(sess);
|
||||||
|
|
||||||
sess.time("assert_dep_graph", || crate::assert_dep_graph(tcx));
|
sess.time("assert_dep_graph", || assert_dep_graph(tcx));
|
||||||
sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx));
|
sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx));
|
||||||
|
|
||||||
if sess.opts.unstable_opts.incremental_info {
|
if sess.opts.unstable_opts.incremental_info {
|
||||||
|
|
|
@ -11,7 +11,8 @@ use rustc_session::Session;
|
||||||
use std::fs as std_fs;
|
use std::fs as std_fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
/// Copies a CGU work product to the incremental compilation directory, so next compilation can find and reuse it.
|
/// Copies a CGU work product to the incremental compilation directory, so next compilation can
|
||||||
|
/// find and reuse it.
|
||||||
pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
|
pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
cgu_name: &str,
|
cgu_name: &str,
|
||||||
|
@ -45,7 +46,7 @@ pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes files for a given work product.
|
/// Removes files for a given work product.
|
||||||
pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
|
pub(crate) fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
|
||||||
for (_, path) in work_product.saved_files.items().into_sorted_stable_ord() {
|
for (_, path) in work_product.saved_files.items().into_sorted_stable_ord() {
|
||||||
let path = in_incr_comp_dir_sess(sess, path);
|
let path = in_incr_comp_dir_sess(sess, path);
|
||||||
if let Err(err) = std_fs::remove_file(&path) {
|
if let Err(err) = std_fs::remove_file(&path) {
|
||||||
|
|
|
@ -614,7 +614,7 @@ fn test_codegen_options_tracking_hash() {
|
||||||
tracked!(force_frame_pointers, Some(false));
|
tracked!(force_frame_pointers, Some(false));
|
||||||
tracked!(force_unwind_tables, Some(true));
|
tracked!(force_unwind_tables, Some(true));
|
||||||
tracked!(inline_threshold, Some(0xf007ba11));
|
tracked!(inline_threshold, Some(0xf007ba11));
|
||||||
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
|
tracked!(instrument_coverage, InstrumentCoverage::All);
|
||||||
tracked!(link_dead_code, Some(true));
|
tracked!(link_dead_code, Some(true));
|
||||||
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
|
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
|
||||||
tracked!(llvm_args, vec![String::from("1"), String::from("2")]);
|
tracked!(llvm_args, vec![String::from("1"), String::from("2")]);
|
||||||
|
|
|
@ -134,7 +134,7 @@ impl FlagComputation {
|
||||||
if should_remove_further_specializable {
|
if should_remove_further_specializable {
|
||||||
self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
|
self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
|
||||||
}
|
}
|
||||||
self.add_flags(TypeFlags::HAS_TY_GENERATOR);
|
self.add_flags(TypeFlags::HAS_TY_COROUTINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
&ty::Closure(_, args) => {
|
&ty::Closure(_, args) => {
|
||||||
|
|
|
@ -48,7 +48,7 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
|
||||||
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
|
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
|
||||||
}
|
}
|
||||||
fn has_coroutines(&self) -> bool {
|
fn has_coroutines(&self) -> bool {
|
||||||
self.has_type_flags(TypeFlags::HAS_TY_GENERATOR)
|
self.has_type_flags(TypeFlags::HAS_TY_COROUTINE)
|
||||||
}
|
}
|
||||||
fn references_error(&self) -> bool {
|
fn references_error(&self) -> bool {
|
||||||
self.has_type_flags(TypeFlags::HAS_ERROR)
|
self.has_type_flags(TypeFlags::HAS_ERROR)
|
||||||
|
|
|
@ -159,8 +159,9 @@ pub struct Parser<'a> {
|
||||||
/// appropriately.
|
/// appropriately.
|
||||||
///
|
///
|
||||||
/// See the comments in the `parse_path_segment` function for more details.
|
/// See the comments in the `parse_path_segment` function for more details.
|
||||||
unmatched_angle_bracket_count: u32,
|
unmatched_angle_bracket_count: u16,
|
||||||
max_angle_bracket_count: u32,
|
max_angle_bracket_count: u16,
|
||||||
|
angle_bracket_nesting: u16,
|
||||||
|
|
||||||
last_unexpected_token_span: Option<Span>,
|
last_unexpected_token_span: Option<Span>,
|
||||||
/// If present, this `Parser` is not parsing Rust code but rather a macro call.
|
/// If present, this `Parser` is not parsing Rust code but rather a macro call.
|
||||||
|
@ -394,6 +395,7 @@ impl<'a> Parser<'a> {
|
||||||
break_last_token: false,
|
break_last_token: false,
|
||||||
unmatched_angle_bracket_count: 0,
|
unmatched_angle_bracket_count: 0,
|
||||||
max_angle_bracket_count: 0,
|
max_angle_bracket_count: 0,
|
||||||
|
angle_bracket_nesting: 0,
|
||||||
last_unexpected_token_span: None,
|
last_unexpected_token_span: None,
|
||||||
subparser_name,
|
subparser_name,
|
||||||
capture_state: CaptureState {
|
capture_state: CaptureState {
|
||||||
|
|
|
@ -487,10 +487,24 @@ impl<'a> Parser<'a> {
|
||||||
// Take a snapshot before attempting to parse - we can restore this later.
|
// Take a snapshot before attempting to parse - we can restore this later.
|
||||||
let snapshot = is_first_invocation.then(|| self.clone());
|
let snapshot = is_first_invocation.then(|| self.clone());
|
||||||
|
|
||||||
|
self.angle_bracket_nesting += 1;
|
||||||
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
|
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
|
||||||
match self.parse_angle_args(ty_generics) {
|
match self.parse_angle_args(ty_generics) {
|
||||||
Ok(args) => Ok(args),
|
Ok(args) => {
|
||||||
|
self.angle_bracket_nesting -= 1;
|
||||||
|
Ok(args)
|
||||||
|
}
|
||||||
|
Err(mut e) if self.angle_bracket_nesting > 10 => {
|
||||||
|
self.angle_bracket_nesting -= 1;
|
||||||
|
// When encountering severely malformed code where there are several levels of
|
||||||
|
// nested unclosed angle args (`f::<f::<f::<f::<...`), we avoid severe O(n^2)
|
||||||
|
// behavior by bailing out earlier (#117080).
|
||||||
|
e.emit();
|
||||||
|
rustc_errors::FatalError.raise();
|
||||||
|
}
|
||||||
Err(e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
|
Err(e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
|
||||||
|
self.angle_bracket_nesting -= 1;
|
||||||
|
|
||||||
// Swap `self` with our backup of the parser state before attempting to parse
|
// Swap `self` with our backup of the parser state before attempting to parse
|
||||||
// generic arguments.
|
// generic arguments.
|
||||||
let snapshot = mem::replace(self, snapshot.unwrap());
|
let snapshot = mem::replace(self, snapshot.unwrap());
|
||||||
|
@ -520,8 +534,8 @@ impl<'a> Parser<'a> {
|
||||||
// Make a span over ${unmatched angle bracket count} characters.
|
// Make a span over ${unmatched angle bracket count} characters.
|
||||||
// This is safe because `all_angle_brackets` ensures that there are only `<`s,
|
// This is safe because `all_angle_brackets` ensures that there are only `<`s,
|
||||||
// i.e. no multibyte characters, in this range.
|
// i.e. no multibyte characters, in this range.
|
||||||
let span =
|
let span = lo
|
||||||
lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
|
.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count.into()));
|
||||||
self.sess.emit_err(errors::UnmatchedAngle {
|
self.sess.emit_err(errors::UnmatchedAngle {
|
||||||
span,
|
span,
|
||||||
plural: snapshot.unmatched_angle_bracket_count > 1,
|
plural: snapshot.unmatched_angle_bracket_count > 1,
|
||||||
|
@ -531,7 +545,10 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_angle_args(ty_generics)
|
self.parse_angle_args(ty_generics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => Err(e),
|
Err(e) => {
|
||||||
|
self.angle_bracket_nesting -= 1;
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -335,7 +335,7 @@ impl Resolver<'_, '_> {
|
||||||
|
|
||||||
for unused in visitor.unused_imports.values() {
|
for unused in visitor.unused_imports.values() {
|
||||||
let mut fixes = Vec::new();
|
let mut fixes = Vec::new();
|
||||||
let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
|
let spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
|
||||||
UnusedSpanResult::Used => continue,
|
UnusedSpanResult::Used => continue,
|
||||||
UnusedSpanResult::FlatUnused(span, remove) => {
|
UnusedSpanResult::FlatUnused(span, remove) => {
|
||||||
fixes.push((remove, String::new()));
|
fixes.push((remove, String::new()));
|
||||||
|
@ -353,20 +353,19 @@ impl Resolver<'_, '_> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let len = spans.len();
|
let ms = MultiSpan::from_spans(spans);
|
||||||
spans.sort();
|
|
||||||
let ms = MultiSpan::from_spans(spans.clone());
|
let mut span_snippets = ms
|
||||||
let mut span_snippets = spans
|
.primary_spans()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|s| match tcx.sess.source_map().span_to_snippet(*s) {
|
.filter_map(|span| tcx.sess.source_map().span_to_snippet(*span).ok())
|
||||||
Ok(s) => Some(format!("`{s}`")),
|
.map(|s| format!("`{s}`"))
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
span_snippets.sort();
|
span_snippets.sort();
|
||||||
|
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"unused import{}{}",
|
"unused import{}{}",
|
||||||
pluralize!(len),
|
pluralize!(ms.primary_spans().len()),
|
||||||
if !span_snippets.is_empty() {
|
if !span_snippets.is_empty() {
|
||||||
format!(": {}", span_snippets.join(", "))
|
format!(": {}", span_snippets.join(", "))
|
||||||
} else {
|
} else {
|
||||||
|
@ -376,7 +375,7 @@ impl Resolver<'_, '_> {
|
||||||
|
|
||||||
let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
|
let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
|
||||||
"remove the whole `use` item"
|
"remove the whole `use` item"
|
||||||
} else if spans.len() > 1 {
|
} else if ms.primary_spans().len() > 1 {
|
||||||
"remove the unused imports"
|
"remove the unused imports"
|
||||||
} else {
|
} else {
|
||||||
"remove the unused import"
|
"remove the unused import"
|
||||||
|
|
|
@ -2743,13 +2743,11 @@ pub fn build_session_options(
|
||||||
// This is what prevents them from being used on stable compilers.
|
// This is what prevents them from being used on stable compilers.
|
||||||
match cg.instrument_coverage {
|
match cg.instrument_coverage {
|
||||||
// Stable values:
|
// Stable values:
|
||||||
Some(InstrumentCoverage::All | InstrumentCoverage::Off) | None => {}
|
InstrumentCoverage::All | InstrumentCoverage::Off => {}
|
||||||
// Unstable values:
|
// Unstable values:
|
||||||
Some(
|
InstrumentCoverage::Branch
|
||||||
InstrumentCoverage::Branch
|
| InstrumentCoverage::ExceptUnusedFunctions
|
||||||
| InstrumentCoverage::ExceptUnusedFunctions
|
| InstrumentCoverage::ExceptUnusedGenerics => {
|
||||||
| InstrumentCoverage::ExceptUnusedGenerics,
|
|
||||||
) => {
|
|
||||||
if !unstable_opts.unstable_options {
|
if !unstable_opts.unstable_options {
|
||||||
handler.early_error(
|
handler.early_error(
|
||||||
"`-C instrument-coverage=branch` and `-C instrument-coverage=except-*` \
|
"`-C instrument-coverage=branch` and `-C instrument-coverage=except-*` \
|
||||||
|
@ -2759,7 +2757,7 @@ pub fn build_session_options(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
|
if cg.instrument_coverage != InstrumentCoverage::Off {
|
||||||
if cg.profile_generate.enabled() || cg.profile_use.is_some() {
|
if cg.profile_generate.enabled() || cg.profile_use.is_some() {
|
||||||
handler.early_error(
|
handler.early_error(
|
||||||
"option `-C instrument-coverage` is not compatible with either `-C profile-use` \
|
"option `-C instrument-coverage` is not compatible with either `-C profile-use` \
|
||||||
|
|
|
@ -294,7 +294,7 @@ impl CodegenOptions {
|
||||||
// JUSTIFICATION: defn of the suggested wrapper fn
|
// JUSTIFICATION: defn of the suggested wrapper fn
|
||||||
#[allow(rustc::bad_opt_access)]
|
#[allow(rustc::bad_opt_access)]
|
||||||
pub fn instrument_coverage(&self) -> InstrumentCoverage {
|
pub fn instrument_coverage(&self) -> InstrumentCoverage {
|
||||||
self.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
|
self.instrument_coverage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -913,23 +913,23 @@ mod parse {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_instrument_coverage(
|
pub(crate) fn parse_instrument_coverage(
|
||||||
slot: &mut Option<InstrumentCoverage>,
|
slot: &mut InstrumentCoverage,
|
||||||
v: Option<&str>,
|
v: Option<&str>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if v.is_some() {
|
if v.is_some() {
|
||||||
let mut bool_arg = None;
|
let mut bool_arg = false;
|
||||||
if parse_opt_bool(&mut bool_arg, v) {
|
if parse_bool(&mut bool_arg, v) {
|
||||||
*slot = bool_arg.unwrap().then_some(InstrumentCoverage::All);
|
*slot = if bool_arg { InstrumentCoverage::All } else { InstrumentCoverage::Off };
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(v) = v else {
|
let Some(v) = v else {
|
||||||
*slot = Some(InstrumentCoverage::All);
|
*slot = InstrumentCoverage::All;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
*slot = Some(match v {
|
*slot = match v {
|
||||||
"all" => InstrumentCoverage::All,
|
"all" => InstrumentCoverage::All,
|
||||||
"branch" => InstrumentCoverage::Branch,
|
"branch" => InstrumentCoverage::Branch,
|
||||||
"except-unused-generics" | "except_unused_generics" => {
|
"except-unused-generics" | "except_unused_generics" => {
|
||||||
|
@ -940,7 +940,7 @@ mod parse {
|
||||||
}
|
}
|
||||||
"off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off,
|
"off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off,
|
||||||
_ => return false,
|
_ => return false,
|
||||||
});
|
};
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1352,7 +1352,7 @@ options! {
|
||||||
inline_threshold: Option<u32> = (None, parse_opt_number, [TRACKED],
|
inline_threshold: Option<u32> = (None, parse_opt_number, [TRACKED],
|
||||||
"set the threshold for inlining a function"),
|
"set the threshold for inlining a function"),
|
||||||
#[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
|
#[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
|
||||||
instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED],
|
instrument_coverage: InstrumentCoverage = (InstrumentCoverage::Off, parse_instrument_coverage, [TRACKED],
|
||||||
"instrument the generated code to support LLVM source-based code coverage \
|
"instrument the generated code to support LLVM source-based code coverage \
|
||||||
reports (note, the compiler build config must include `profiler = true`); \
|
reports (note, the compiler build config must include `profiler = true`); \
|
||||||
implies `-C symbol-mangling-version=v0`. Optional values are:
|
implies `-C symbol-mangling-version=v0`. Optional values are:
|
||||||
|
|
|
@ -287,9 +287,8 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
|
||||||
type T = stable_mir::mir::Body;
|
type T = stable_mir::mir::Body;
|
||||||
|
|
||||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
stable_mir::mir::Body {
|
stable_mir::mir::Body::new(
|
||||||
blocks: self
|
self.basic_blocks
|
||||||
.basic_blocks
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|block| stable_mir::mir::BasicBlock {
|
.map(|block| stable_mir::mir::BasicBlock {
|
||||||
terminator: block.terminator().stable(tables),
|
terminator: block.terminator().stable(tables),
|
||||||
|
@ -300,15 +299,15 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
|
||||||
.collect(),
|
.collect(),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
locals: self
|
self.local_decls
|
||||||
.local_decls
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|decl| stable_mir::mir::LocalDecl {
|
.map(|decl| stable_mir::mir::LocalDecl {
|
||||||
ty: decl.ty.stable(tables),
|
ty: decl.ty.stable(tables),
|
||||||
span: decl.source_info.span.stable(tables),
|
span: decl.source_info.span.stable(tables),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
self.arg_count,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ bitflags! {
|
||||||
/// Does this value have `InferConst::Fresh`?
|
/// Does this value have `InferConst::Fresh`?
|
||||||
const HAS_CT_FRESH = 1 << 22;
|
const HAS_CT_FRESH = 1 << 22;
|
||||||
|
|
||||||
/// Does this have `Generator` or `GeneratorWitness`?
|
/// Does this have `Coroutine` or `CoroutineWitness`?
|
||||||
const HAS_TY_GENERATOR = 1 << 23;
|
const HAS_TY_COROUTINE = 1 << 23;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,60 @@ use crate::ty::{AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability
|
||||||
use crate::Opaque;
|
use crate::Opaque;
|
||||||
use crate::{ty::Ty, Span};
|
use crate::{ty::Ty, Span};
|
||||||
|
|
||||||
|
/// The SMIR representation of a single function.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Body {
|
pub struct Body {
|
||||||
pub blocks: Vec<BasicBlock>,
|
pub blocks: Vec<BasicBlock>,
|
||||||
pub locals: LocalDecls,
|
|
||||||
|
// Declarations of locals within the function.
|
||||||
|
//
|
||||||
|
// The first local is the return value pointer, followed by `arg_count`
|
||||||
|
// locals for the function arguments, followed by any user-declared
|
||||||
|
// variables and temporaries.
|
||||||
|
locals: LocalDecls,
|
||||||
|
|
||||||
|
// The number of arguments this function takes.
|
||||||
|
arg_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Body {
|
||||||
|
/// Constructs a `Body`.
|
||||||
|
///
|
||||||
|
/// A constructor is required to build a `Body` from outside the crate
|
||||||
|
/// because the `arg_count` and `locals` fields are private.
|
||||||
|
pub fn new(blocks: Vec<BasicBlock>, locals: LocalDecls, arg_count: usize) -> Self {
|
||||||
|
// If locals doesn't contain enough entries, it can lead to panics in
|
||||||
|
// `ret_local`, `arg_locals`, and `inner_locals`.
|
||||||
|
assert!(
|
||||||
|
locals.len() > arg_count,
|
||||||
|
"A Body must contain at least a local for the return value and each of the function's arguments"
|
||||||
|
);
|
||||||
|
Self { blocks, locals, arg_count }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return local that holds this function's return value.
|
||||||
|
pub fn ret_local(&self) -> &LocalDecl {
|
||||||
|
&self.locals[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Locals in `self` that correspond to this function's arguments.
|
||||||
|
pub fn arg_locals(&self) -> &[LocalDecl] {
|
||||||
|
&self.locals[1..][..self.arg_count]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inner locals for this function. These are the locals that are
|
||||||
|
/// neither the return local nor the argument locals.
|
||||||
|
pub fn inner_locals(&self) -> &[LocalDecl] {
|
||||||
|
&self.locals[self.arg_count + 1..]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience function to get all the locals in this function.
|
||||||
|
///
|
||||||
|
/// Locals are typically accessed via the more specific methods `ret_local`,
|
||||||
|
/// `arg_locals`, and `inner_locals`.
|
||||||
|
pub fn locals(&self) -> &[LocalDecl] {
|
||||||
|
&self.locals
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type LocalDecls = Vec<LocalDecl>;
|
type LocalDecls = Vec<LocalDecl>;
|
||||||
|
@ -467,7 +517,7 @@ pub enum NullOp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operand {
|
impl Operand {
|
||||||
pub fn ty(&self, locals: &LocalDecls) -> Ty {
|
pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
|
||||||
match self {
|
match self {
|
||||||
Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
|
Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
|
||||||
Operand::Constant(c) => c.ty(),
|
Operand::Constant(c) => c.ty(),
|
||||||
|
@ -482,7 +532,7 @@ impl Constant {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Place {
|
impl Place {
|
||||||
pub fn ty(&self, locals: &LocalDecls) -> Ty {
|
pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
|
||||||
let _start_ty = locals[self.local].ty;
|
let _start_ty = locals[self.local].ty;
|
||||||
todo!("Implement projection")
|
todo!("Implement projection")
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ fn test_body(body: mir::Body) {
|
||||||
for term in body.blocks.iter().map(|bb| &bb.terminator) {
|
for term in body.blocks.iter().map(|bb| &bb.terminator) {
|
||||||
match &term.kind {
|
match &term.kind {
|
||||||
Call { func, .. } => {
|
Call { func, .. } => {
|
||||||
let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() };
|
let TyKind::RigidTy(ty) = func.ty(body.locals()).kind() else { unreachable!() };
|
||||||
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
|
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
|
||||||
let result = Instance::resolve(def, &args);
|
let result = Instance::resolve(def, &args);
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
|
@ -47,7 +47,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||||
|
|
||||||
let bar = get_item(&items, (DefKind::Fn, "bar")).unwrap();
|
let bar = get_item(&items, (DefKind::Fn, "bar")).unwrap();
|
||||||
let body = bar.body();
|
let body = bar.body();
|
||||||
assert_eq!(body.locals.len(), 2);
|
assert_eq!(body.locals().len(), 2);
|
||||||
assert_eq!(body.blocks.len(), 1);
|
assert_eq!(body.blocks.len(), 1);
|
||||||
let block = &body.blocks[0];
|
let block = &body.blocks[0];
|
||||||
assert_eq!(block.statements.len(), 1);
|
assert_eq!(block.statements.len(), 1);
|
||||||
|
@ -62,7 +62,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||||
|
|
||||||
let foo_bar = get_item(&items, (DefKind::Fn, "foo_bar")).unwrap();
|
let foo_bar = get_item(&items, (DefKind::Fn, "foo_bar")).unwrap();
|
||||||
let body = foo_bar.body();
|
let body = foo_bar.body();
|
||||||
assert_eq!(body.locals.len(), 5);
|
assert_eq!(body.locals().len(), 5);
|
||||||
assert_eq!(body.blocks.len(), 4);
|
assert_eq!(body.blocks.len(), 4);
|
||||||
let block = &body.blocks[0];
|
let block = &body.blocks[0];
|
||||||
match &block.terminator.kind {
|
match &block.terminator.kind {
|
||||||
|
@ -72,29 +72,29 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||||
|
|
||||||
let types = get_item(&items, (DefKind::Fn, "types")).unwrap();
|
let types = get_item(&items, (DefKind::Fn, "types")).unwrap();
|
||||||
let body = types.body();
|
let body = types.body();
|
||||||
assert_eq!(body.locals.len(), 6);
|
assert_eq!(body.locals().len(), 6);
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
body.locals[0].ty.kind(),
|
body.locals()[0].ty.kind(),
|
||||||
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool)
|
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool)
|
||||||
);
|
);
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
body.locals[1].ty.kind(),
|
body.locals()[1].ty.kind(),
|
||||||
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool)
|
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool)
|
||||||
);
|
);
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
body.locals[2].ty.kind(),
|
body.locals()[2].ty.kind(),
|
||||||
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Char)
|
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Char)
|
||||||
);
|
);
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
body.locals[3].ty.kind(),
|
body.locals()[3].ty.kind(),
|
||||||
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Int(stable_mir::ty::IntTy::I32))
|
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Int(stable_mir::ty::IntTy::I32))
|
||||||
);
|
);
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
body.locals[4].ty.kind(),
|
body.locals()[4].ty.kind(),
|
||||||
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Uint(stable_mir::ty::UintTy::U64))
|
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Uint(stable_mir::ty::UintTy::U64))
|
||||||
);
|
);
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
body.locals[5].ty.kind(),
|
body.locals()[5].ty.kind(),
|
||||||
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Float(
|
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Float(
|
||||||
stable_mir::ty::FloatTy::F64
|
stable_mir::ty::FloatTy::F64
|
||||||
))
|
))
|
||||||
|
@ -123,10 +123,10 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||||
for block in instance.body().blocks {
|
for block in instance.body().blocks {
|
||||||
match &block.terminator.kind {
|
match &block.terminator.kind {
|
||||||
stable_mir::mir::TerminatorKind::Call { func, .. } => {
|
stable_mir::mir::TerminatorKind::Call { func, .. } => {
|
||||||
let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() };
|
let TyKind::RigidTy(ty) = func.ty(&body.locals()).kind() else { unreachable!() };
|
||||||
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
|
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
|
||||||
let next_func = Instance::resolve(def, &args).unwrap();
|
let next_func = Instance::resolve(def, &args).unwrap();
|
||||||
match next_func.body().locals[1].ty.kind() {
|
match next_func.body().locals()[1].ty.kind() {
|
||||||
TyKind::RigidTy(RigidTy::Uint(_)) | TyKind::RigidTy(RigidTy::Tuple(_)) => {}
|
TyKind::RigidTy(RigidTy::Uint(_)) | TyKind::RigidTy(RigidTy::Tuple(_)) => {}
|
||||||
other => panic!("{other:?}"),
|
other => panic!("{other:?}"),
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,29 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||||
// Ensure we don't panic trying to get the body of a constant.
|
// Ensure we don't panic trying to get the body of a constant.
|
||||||
foo_const.body();
|
foo_const.body();
|
||||||
|
|
||||||
|
let locals_fn = get_item(&items, (DefKind::Fn, "locals")).unwrap();
|
||||||
|
let body = locals_fn.body();
|
||||||
|
assert_eq!(body.locals().len(), 4);
|
||||||
|
assert_matches!(
|
||||||
|
body.ret_local().ty.kind(),
|
||||||
|
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Char)
|
||||||
|
);
|
||||||
|
assert_eq!(body.arg_locals().len(), 2);
|
||||||
|
assert_matches!(
|
||||||
|
body.arg_locals()[0].ty.kind(),
|
||||||
|
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Int(stable_mir::ty::IntTy::I32))
|
||||||
|
);
|
||||||
|
assert_matches!(
|
||||||
|
body.arg_locals()[1].ty.kind(),
|
||||||
|
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Uint(stable_mir::ty::UintTy::U64))
|
||||||
|
);
|
||||||
|
assert_eq!(body.inner_locals().len(), 1);
|
||||||
|
// If conditions have an extra inner local to hold their results
|
||||||
|
assert_matches!(
|
||||||
|
body.inner_locals()[0].ty.kind(),
|
||||||
|
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool)
|
||||||
|
);
|
||||||
|
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,6 +234,14 @@ fn generate_input(path: &str) -> std::io::Result<()> {
|
||||||
|
|
||||||
pub fn assert(x: i32) -> i32 {{
|
pub fn assert(x: i32) -> i32 {{
|
||||||
x + 1
|
x + 1
|
||||||
|
}}
|
||||||
|
|
||||||
|
pub fn locals(a: i32, _: u64) -> char {{
|
||||||
|
if a > 5 {{
|
||||||
|
'a'
|
||||||
|
}} else {{
|
||||||
|
'b'
|
||||||
|
}}
|
||||||
}}"#
|
}}"#
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -29,7 +29,7 @@ const CRATE_NAME: &str = "input";
|
||||||
fn test_translation(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
fn test_translation(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||||
let main_fn = stable_mir::entry_fn().unwrap();
|
let main_fn = stable_mir::entry_fn().unwrap();
|
||||||
let body = main_fn.body();
|
let body = main_fn.body();
|
||||||
let orig_ty = body.locals[0].ty;
|
let orig_ty = body.locals()[0].ty;
|
||||||
let rustc_ty = rustc_internal::internal(&orig_ty);
|
let rustc_ty = rustc_internal::internal(&orig_ty);
|
||||||
assert!(rustc_ty.is_unit());
|
assert!(rustc_ty.is_unit());
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
|
|
19
tests/ui/lifetimes/issue-76168-hr-outlives-3.rs
Normal file
19
tests/ui/lifetimes/issue-76168-hr-outlives-3.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
#![feature(unboxed_closures)]
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
async fn wrapper<F>(f: F)
|
||||||
|
//~^ ERROR: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32`
|
||||||
|
//~| ERROR: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32`
|
||||||
|
//~| ERROR: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32`
|
||||||
|
where
|
||||||
|
F:,
|
||||||
|
for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
|
||||||
|
{
|
||||||
|
//~^ ERROR: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32`
|
||||||
|
let mut i = 41;
|
||||||
|
&mut i;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
51
tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr
Normal file
51
tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
error[E0277]: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32`
|
||||||
|
--> $DIR/issue-76168-hr-outlives-3.rs:6:1
|
||||||
|
|
|
||||||
|
LL | / async fn wrapper<F>(f: F)
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | where
|
||||||
|
LL | | F:,
|
||||||
|
LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
|
||||||
|
| |______________________________________________________________________________^ expected an `FnOnce<(&'a mut i32,)>` closure, found `i32`
|
||||||
|
|
|
||||||
|
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
|
||||||
|
|
||||||
|
error[E0277]: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32`
|
||||||
|
--> $DIR/issue-76168-hr-outlives-3.rs:6:10
|
||||||
|
|
|
||||||
|
LL | async fn wrapper<F>(f: F)
|
||||||
|
| ^^^^^^^ expected an `FnOnce<(&'a mut i32,)>` closure, found `i32`
|
||||||
|
|
|
||||||
|
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
|
||||||
|
|
||||||
|
error[E0277]: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32`
|
||||||
|
--> $DIR/issue-76168-hr-outlives-3.rs:13:1
|
||||||
|
|
|
||||||
|
LL | / {
|
||||||
|
LL | |
|
||||||
|
LL | | let mut i = 41;
|
||||||
|
LL | | &mut i;
|
||||||
|
LL | | }
|
||||||
|
| |_^ expected an `FnOnce<(&'a mut i32,)>` closure, found `i32`
|
||||||
|
|
|
||||||
|
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
|
||||||
|
|
||||||
|
error[E0277]: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32`
|
||||||
|
--> $DIR/issue-76168-hr-outlives-3.rs:6:1
|
||||||
|
|
|
||||||
|
LL | / async fn wrapper<F>(f: F)
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | where
|
||||||
|
LL | | F:,
|
||||||
|
LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
|
||||||
|
| |______________________________________________________________________________^ expected an `FnOnce<(&'a mut i32,)>` closure, found `i32`
|
||||||
|
|
|
||||||
|
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32`
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
17
tests/ui/parser/deep-unmatched-angle-brackets.rs
Normal file
17
tests/ui/parser/deep-unmatched-angle-brackets.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
trait Mul<T> {
|
||||||
|
type Output;
|
||||||
|
}
|
||||||
|
trait Matrix: Mul<<Self as Matrix>::Row, Output = ()> {
|
||||||
|
type Row;
|
||||||
|
type Transpose: Matrix<Row = Self::Row>;
|
||||||
|
}
|
||||||
|
fn is_mul<S, T: Mul<S, Output = ()>>() {}
|
||||||
|
fn f<T: Matrix>() {
|
||||||
|
is_mul::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<
|
||||||
|
f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<
|
||||||
|
f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<
|
||||||
|
f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::
|
||||||
|
<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<>();
|
||||||
|
//~^ ERROR expected one of `!`, `+`, `,`, `::`, or `>`, found `(`
|
||||||
|
}
|
||||||
|
fn main() {}
|
13
tests/ui/parser/deep-unmatched-angle-brackets.stderr
Normal file
13
tests/ui/parser/deep-unmatched-angle-brackets.stderr
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
error: expected one of `!`, `+`, `,`, `::`, or `>`, found `(`
|
||||||
|
--> $DIR/deep-unmatched-angle-brackets.rs:14:63
|
||||||
|
|
|
||||||
|
LL | <f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<>();
|
||||||
|
| ^ expected one of `!`, `+`, `,`, `::`, or `>`
|
||||||
|
|
|
||||||
|
help: you might have meant to end the type parameters here
|
||||||
|
|
|
||||||
|
LL | <f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<>>();
|
||||||
|
| +
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue