diff --git a/Cargo.lock b/Cargo.lock index ce1f705bdffad..85be4c392afae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4011,6 +4011,7 @@ dependencies = [ "rustc_errors", "rustc_hir", "rustc_index", + "rustc_lexer", "rustc_middle", "rustc_serialize", "rustc_session", diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 314e5103cc2de..e0e78a4d60953 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -347,7 +347,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `_ => else_block` where `else_block` is `{}` if there's `None`: let else_pat = self.pat_wild(span); let (else_expr, contains_else_clause) = match else_opt { - None => (self.expr_block_empty(span), false), + None => (self.expr_block_empty(span.shrink_to_hi()), false), Some(els) => (self.lower_expr(els), true), }; let else_arm = self.arm(else_pat, else_expr); diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 62a7986c194f0..97c38e04bc182 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -127,9 +127,6 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { return; } - // FIXME(richkadel): Make sure probestack plays nice with `-Z instrument-coverage` - // or disable it if not, similar to above early exits. - // Flag our internal `__rust_probestack` function as the stack probe symbol. // This is defined in the `compiler-builtins` crate for each architecture. llvm::AddFunctionAttrStringValue( diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 85aaa7e8893bf..1c7e727f9b0b9 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -3,11 +3,14 @@ use crate::coverageinfo; use crate::llvm; use llvm::coverageinfo::CounterMappingRegion; -use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression}; +use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression, FunctionCoverage}; use rustc_codegen_ssa::traits::ConstMethods; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_llvm::RustString; use rustc_middle::mir::coverage::CodeRegion; +use rustc_middle::ty::{Instance, TyCtxt}; +use rustc_span::Symbol; use std::ffi::CString; @@ -26,14 +29,17 @@ use tracing::debug; /// undocumented details in Clang's implementation (that may or may not be important) were also /// replicated for Rust's Coverage Map. pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { + let tcx = cx.tcx; // Ensure LLVM supports Coverage Map Version 4 (encoded as a zero-based value: 3). // If not, the LLVM Version must be less than 11. let version = coverageinfo::mapping_version(); if version != 3 { - cx.tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); + tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher."); } - let function_coverage_map = match cx.coverage_context() { + debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name()); + + let mut function_coverage_map = match cx.coverage_context() { Some(ctx) => ctx.take_function_coverage_map(), None => return, }; @@ -42,14 +48,15 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { return; } + add_unreachable_coverage(tcx, &mut function_coverage_map); + let mut mapgen = CoverageMapGenerator::new(); // Encode coverage mappings and generate function records let mut function_data = Vec::new(); for (instance, function_coverage) in function_coverage_map { - debug!("Generate coverage map for: {:?}", instance); - - let mangled_function_name = cx.tcx.symbol_name(instance).to_string(); + debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance); + let mangled_function_name = tcx.symbol_name(instance).to_string(); let function_source_hash = function_coverage.source_hash(); let (expressions, counter_regions) = function_coverage.get_expressions_and_counter_regions(); @@ -228,3 +235,156 @@ fn save_function_record( let is_used = true; coverageinfo::save_func_record_to_mod(cx, func_name_hash, func_record_val, is_used); } + +/// When finalizing the coverage map, `FunctionCoverage` only has the `CodeRegion`s and counters for +/// the functions that went through codegen; such as public functions and "used" functions +/// (functions referenced by other "used" or public items). Any other functions considered unused, +/// or "Unreachable" were still parsed and processed through the MIR stage. +/// +/// We can find the unreachable functions by the set different of all MIR `DefId`s (`tcx` query +/// `mir_keys`) minus the codegenned `DefId`s (`tcx` query `collect_and_partition_mono_items`). +/// +/// *HOWEVER* the codegenned `DefId`s are partitioned across multiple `CodegenUnit`s (CGUs), and +/// this function is processing a `function_coverage_map` for the functions (`Instance`/`DefId`) +/// allocated to only one of those CGUs. We must NOT inject any "Unreachable" functions's +/// `CodeRegion`s more than once, so we have to pick which CGU's `function_coverage_map` to add +/// each "Unreachable" function to. +/// +/// Some constraints: +/// +/// 1. The file name of an "Unreachable" function must match the file name of the existing +/// codegenned (covered) function to which the unreachable code regions will be added. +/// 2. The function to which the unreachable code regions will be added must not be a genaric +/// function (must not have type parameters) because the coverage tools will get confused +/// if the codegenned function has more than one instantiation and additional `CodeRegion`s +/// attached to only one of those instantiations. +fn add_unreachable_coverage<'tcx>( + tcx: TyCtxt<'tcx>, + function_coverage_map: &mut FxHashMap, FunctionCoverage<'tcx>>, +) { + // FIXME(#79622): Can this solution be simplified and/or improved? Are there other sources + // of compiler state data that might help (or better sources that could be exposed, but + // aren't yet)? + + // Note: If the crate *only* defines generic functions, there are no codegenerated non-generic + // functions to add any unreachable code to. In this case, the unreachable code regions will + // have no coverage, instead of having coverage with zero executions. + // + // This is probably still an improvement over Clang, which does not generate any coverage + // for uninstantiated template functions. + + let has_non_generic_def_ids = + function_coverage_map.keys().any(|instance| instance.def.attrs(tcx).len() == 0); + + if !has_non_generic_def_ids { + // There are no non-generic functions to add unreachable `CodeRegion`s to + return; + } + + let all_def_ids: DefIdSet = + tcx.mir_keys(LOCAL_CRATE).iter().map(|local_def_id| local_def_id.to_def_id()).collect(); + + let (codegenned_def_ids, _) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); + + let mut unreachable_def_ids_by_file: FxHashMap> = FxHashMap::default(); + for &non_codegenned_def_id in all_def_ids.difference(codegenned_def_ids) { + // Make sure the non-codegenned (unreachable) function has a file_name + if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) { + let def_ids = unreachable_def_ids_by_file + .entry(*non_codegenned_file_name) + .or_insert_with(|| Vec::new()); + def_ids.push(non_codegenned_def_id); + } + } + + if unreachable_def_ids_by_file.is_empty() { + // There are no unreachable functions with file names to add (in any CGU) + return; + } + + // Since there may be multiple `CodegenUnit`s, some codegenned_def_ids may be codegenned in a + // different CGU, and will be added to the function_coverage_map for each CGU. Determine which + // function_coverage_map has the responsibility for publishing unreachable coverage + // based on file name: + // + // For each covered file name, sort ONLY the non-generic codegenned_def_ids, and if + // covered_def_ids.contains(the first def_id) for a given file_name, add the unreachable code + // region in this function_coverage_map. Otherwise, ignore it and assume another CGU's + // function_coverage_map will be adding it (because it will be first for one, and only one, + // of them). + let mut sorted_codegenned_def_ids: Vec = + codegenned_def_ids.iter().map(|def_id| *def_id).collect(); + sorted_codegenned_def_ids.sort_unstable(); + + let mut first_covered_def_id_by_file: FxHashMap = FxHashMap::default(); + for &def_id in sorted_codegenned_def_ids.iter() { + // Only consider non-generic functions, to potentially add unreachable code regions + if tcx.generics_of(def_id).count() == 0 { + if let Some(covered_file_name) = tcx.covered_file_name(def_id) { + // Only add files known to have unreachable functions + if unreachable_def_ids_by_file.contains_key(covered_file_name) { + first_covered_def_id_by_file.entry(*covered_file_name).or_insert(def_id); + } + } + } + } + + // Get the set of def_ids with coverage regions, known by *this* CoverageContext. + let cgu_covered_def_ids: DefIdSet = + function_coverage_map.keys().map(|instance| instance.def.def_id()).collect(); + + let mut cgu_covered_files: FxHashSet = first_covered_def_id_by_file + .iter() + .filter_map( + |(&file_name, def_id)| { + if cgu_covered_def_ids.contains(def_id) { Some(file_name) } else { None } + }, + ) + .collect(); + + // Find the first covered, non-generic function (instance) for each cgu_covered_file. Take the + // unreachable code regions for that file, and add them to the function. + // + // There are three `for` loops here, but (a) the lists have already been reduced to the minimum + // required values, the lists are further reduced (by `remove()` calls) when elements are no + // longer needed, and there are several opportunities to branch out of loops early. + for (instance, function_coverage) in function_coverage_map.iter_mut() { + if instance.def.attrs(tcx).len() > 0 { + continue; + } + // The covered function is not generic... + let covered_def_id = instance.def.def_id(); + if let Some(covered_file_name) = tcx.covered_file_name(covered_def_id) { + if !cgu_covered_files.remove(&covered_file_name) { + continue; + } + // The covered function's file is one of the files with unreachable code regions, so + // all of the unreachable code regions for this file will be added to this function. + for def_id in + unreachable_def_ids_by_file.remove(&covered_file_name).into_iter().flatten() + { + // Note, this loop adds an unreachable code regions for each MIR-derived region. + // Alternatively, we could add a single code region for the maximum span of all + // code regions here. + // + // Observed downsides of this approach are: + // + // 1. The coverage results will appear inconsistent compared with the same (or + // similar) code in a function that is reached. + // 2. If the function is unreachable from one crate but reachable when compiling + // another referencing crate (such as a cross-crate reference to a + // generic function or inlined function), actual coverage regions overlaid + // on a single larger code span of `Zero` coverage can appear confusing or + // wrong. Chaning the unreachable coverage from a `code_region` to a + // `gap_region` can help, but still can look odd with `0` line counts for + // lines between executed (> 0) lines (such as for blank lines or comments). + for ®ion in tcx.covered_code_regions(def_id) { + function_coverage.add_unreachable_region(region.clone()); + } + } + if cgu_covered_files.is_empty() { + break; + } + } + } +} diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 70b92b234e94c..8ec1eed440456 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -2,6 +2,7 @@ #![feature(bool_to_option)] #![feature(option_expect_none)] #![feature(box_patterns)] +#![feature(drain_filter)] #![feature(try_blocks)] #![feature(in_band_lifetimes)] #![feature(nll)] diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index c1741bfaabad2..b3466f49b9f25 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -223,7 +223,6 @@ fn run_compiler( file_loader: None, diagnostic_output, stderr: None, - crate_name: None, lint_caps: Default::default(), register_lints: None, override_queries: None, @@ -307,7 +306,6 @@ fn run_compiler( file_loader, diagnostic_output, stderr: None, - crate_name: None, lint_caps: Default::default(), register_lints: None, override_queries: None, diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 0a88759f84c9a..636c37142ad9a 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -283,6 +283,7 @@ E0537: include_str!("./error_codes/E0537.md"), E0538: include_str!("./error_codes/E0538.md"), E0539: include_str!("./error_codes/E0539.md"), E0541: include_str!("./error_codes/E0541.md"), +E0546: include_str!("./error_codes/E0546.md"), E0550: include_str!("./error_codes/E0550.md"), E0551: include_str!("./error_codes/E0551.md"), E0552: include_str!("./error_codes/E0552.md"), @@ -603,7 +604,6 @@ E0779: include_str!("./error_codes/E0779.md"), E0543, // missing 'reason' E0544, // multiple stability levels E0545, // incorrect 'issue' - E0546, // missing 'feature' E0547, // missing 'issue' // E0548, // replaced with a generic attribute input check // rustc_deprecated attribute must be paired with either stable or unstable diff --git a/compiler/rustc_error_codes/src/error_codes/E0546.md b/compiler/rustc_error_codes/src/error_codes/E0546.md new file mode 100644 index 0000000000000..b2df22c0f8fad --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0546.md @@ -0,0 +1,27 @@ +A feature name is missing. + +Erroneous code example: + +```compile_fail,E0546 +#![feature(staged_api)] +#![stable(since = "1.0.0", feature = "test")] + +#[unstable(issue = "none")] // invalid +fn unstable_fn() {} + +#[stable(since = "1.0.0")] // invalid +fn stable_fn() {} +``` + +To fix the issue you need to provide a feature name. + +``` +#![feature(staged_api)] +#![stable(since = "1.0.0", feature = "test")] + +#[unstable(feature = "unstable_fn", issue = "none")] // ok! +fn unstable_fn() {} + +#[stable(feature = "stable_fn", since = "1.0.0")] // ok! +fn stable_fn() {} +``` diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b1071bf430851..335f3b7a9a011 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -235,12 +235,10 @@ impl Annotatable { pub fn derive_allowed(&self) -> bool { match *self { Annotatable::Stmt(ref stmt) => match stmt.kind { - ast::StmtKind::Item(ref item) => match item.kind { - ast::ItemKind::Struct(..) - | ast::ItemKind::Enum(..) - | ast::ItemKind::Union(..) => true, - _ => false, - }, + ast::StmtKind::Item(ref item) => matches!( + item.kind, + ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) + ), _ => false, }, Annotatable::Item(ref item) => match item.kind { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 37ff6b9b368e7..2da5bde028fc1 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1134,7 +1134,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { if let Some(attr) = self.take_first_attr_no_derive(&mut expr) { // Collect the invoc regardless of whether or not attributes are permitted here // expansion will eat the attribute so it won't error later. - attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr)); + if let Some(attr) = attr.0.as_ref() { + self.cfg.maybe_emit_expr_attr_err(attr) + } // AstFragmentKind::Expr requires the macro to emit an expression. return self @@ -1231,7 +1233,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.cfg.configure_expr_kind(&mut expr.kind); if let Some(attr) = self.take_first_attr_no_derive(&mut expr) { - attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr)); + if let Some(attr) = attr.0.as_ref() { + self.cfg.maybe_emit_expr_attr_err(attr) + } return self .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f01d44171056f..44dc6673564a5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2401,7 +2401,7 @@ impl StructField<'_> { // Still necessary in couple of places pub fn is_positional(&self) -> bool { let first = self.ident.as_str().as_bytes()[0]; - first >= b'0' && first <= b'9' + (b'0'..=b'9').contains(&first) } } diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index 9d9ecf5b384e7..39043980dc4f1 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -24,9 +24,9 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { // as-is, we need to do some extra work here in order to make sure // that function subtyping works correctly with respect to regions // - // Note: this is a subtle algorithm. For a full explanation, - // please see the large comment at the end of the file in the (inlined) module - // `doc`. + // Note: this is a subtle algorithm. For a full explanation, please see + // the rustc dev guide: + // let span = self.trace.cause.span; diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 93863ef1d50c8..8273c2d291d09 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,10 +1,9 @@ use smallvec::smallvec; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::outlives::Component; use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness}; -use rustc_span::symbol::Ident; pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, @@ -288,37 +287,6 @@ pub fn transitive_bounds<'tcx>( elaborate_trait_refs(tcx, bounds).filter_to_traits() } -/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may -/// define the given associated type `assoc_name`. It uses the -/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that -/// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or -/// `T::Item` and helps to avoid cycle errors (see e.g. #35237). -pub fn transitive_bounds_that_define_assoc_type<'tcx>( - tcx: TyCtxt<'tcx>, - bounds: impl Iterator>, - assoc_name: Ident, -) -> FxIndexSet> { - let mut stack: Vec<_> = bounds.collect(); - let mut trait_refs = FxIndexSet::default(); - - while let Some(trait_ref) = stack.pop() { - if trait_refs.insert(trait_ref) { - let super_predicates = - tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), Some(assoc_name))); - for (super_predicate, _) in super_predicates.predicates { - let bound_predicate = super_predicate.bound_atom(); - let subst_predicate = super_predicate - .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder())); - if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() { - stack.push(binder.value); - } - } - } - } - - trait_refs -} - /////////////////////////////////////////////////////////////////////////// // Other /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 11dd6ec32c094..acd49d86c2c84 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -34,7 +34,6 @@ pub struct Compiler { pub(crate) input_path: Option, pub(crate) output_dir: Option, pub(crate) output_file: Option, - pub(crate) crate_name: Option, pub(crate) register_lints: Option>, pub(crate) override_queries: Option, @@ -140,7 +139,6 @@ pub struct Config { /// Set to capture stderr output during compiler execution pub stderr: Option>>>, - pub crate_name: Option, pub lint_caps: FxHashMap, /// This is a callback from the driver that is called when we're registering lints; @@ -185,7 +183,6 @@ pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R input_path: config.input_path, output_dir: config.output_dir, output_file: config.output_file, - crate_name: config.crate_name, register_lints: config.register_lints, override_queries: config.override_queries, }; diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index a2704c3adbf00..4c340b3fc1f58 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -156,13 +156,11 @@ impl<'tcx> Queries<'tcx> { pub fn crate_name(&self) -> Result<&Query> { self.crate_name.compute(|| { - Ok(match self.compiler.crate_name { - Some(ref crate_name) => crate_name.clone(), - None => { - let parse_result = self.parse()?; - let krate = parse_result.peek(); - find_crate_name(self.session(), &krate.attrs, &self.compiler.input) - } + Ok({ + let parse_result = self.parse()?; + let krate = parse_result.peek(); + // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. + find_crate_name(self.session(), &krate.attrs, &self.compiler.input) }) }) } diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 6539419aefb27..44fc4db7dc199 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -267,8 +267,8 @@ pub fn is_whitespace(c: char) -> bool { pub fn is_id_start(c: char) -> bool { // This is XID_Start OR '_' (which formally is not a XID_Start). // We also add fast-path for ascii idents - ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') + ('a'..='z').contains(&c) + || ('A'..='Z').contains(&c) || c == '_' || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_start(c)) } @@ -279,9 +279,9 @@ pub fn is_id_start(c: char) -> bool { pub fn is_id_continue(c: char) -> bool { // This is exactly XID_Continue. // We also add fast-path for ascii idents - ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') - || ('0' <= c && c <= '9') + ('a'..='z').contains(&c) + || ('A'..='Z').contains(&c) + || ('0'..='9').contains(&c) || c == '_' || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_continue(c)) } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index c2d98b8e4ad37..af5972c6c81c7 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -10,7 +10,7 @@ use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; declare_tool_lint! { pub rustc::DEFAULT_HASH_TYPES, @@ -267,3 +267,47 @@ impl EarlyLintPass for LintPassImpl { } } } + +declare_tool_lint! { + pub rustc::EXISTING_DOC_KEYWORD, + Allow, + "Check that documented keywords in std and core actually exist", + report_in_external_macro: true +} + +declare_lint_pass!(ExistingDocKeyword => [EXISTING_DOC_KEYWORD]); + +fn is_doc_keyword(s: Symbol) -> bool { + s <= kw::Union +} + +impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { + fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { + for attr in item.attrs { + if !attr.has_name(sym::doc) { + continue; + } + if let Some(list) = attr.meta_item_list() { + for nested in list { + if nested.has_name(sym::keyword) { + let v = nested + .value_str() + .expect("#[doc(keyword = \"...\")] expected a value!"); + if is_doc_keyword(v) { + return; + } + cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| { + lint.build(&format!( + "Found non-existing keyword `{}` used in \ + `#[doc(keyword = \"...\")]`", + v, + )) + .help("only existing keywords are allowed in core/std") + .emit(); + }); + } + } + } + } + } +} diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 02da85d25d5c5..3e22eba15aaef 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -108,18 +108,32 @@ impl<'s> LintLevelsBuilder<'s> { id: LintId, (level, src): LevelSource, ) { - if let Some((old_level, old_src)) = specs.get(&id) { - if old_level == &Level::Forbid && level != Level::Forbid { + // Setting to a non-forbid level is an error if the lint previously had + // a forbid level. Note that this is not necessarily true even with a + // `#[forbid(..)]` attribute present, as that is overriden by `--cap-lints`. + // + // This means that this only errors if we're truly lowering the lint + // level from forbid. + if level != Level::Forbid { + if let (Level::Forbid, old_src) = + self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess) + { let mut diag_builder = struct_span_err!( self.sess, src.span(), E0453, - "{}({}) incompatible with previous forbid in same scope", + "{}({}) incompatible with previous forbid", level.as_str(), src.name(), ); - match *old_src { - LintSource::Default => {} + diag_builder.span_label(src.span(), "overruled by previous forbid"); + match old_src { + LintSource::Default => { + diag_builder.note(&format!( + "`forbid` lint level is the default for {}", + id.to_string() + )); + } LintSource::Node(_, forbid_source_span, reason) => { diag_builder.span_label(forbid_source_span, "`forbid` level set here"); if let Some(rationale) = reason { @@ -131,6 +145,8 @@ impl<'s> LintLevelsBuilder<'s> { } } diag_builder.emit(); + + // Retain the forbid lint level return; } } @@ -414,50 +430,6 @@ impl<'s> LintLevelsBuilder<'s> { } } - for (id, &(level, ref src)) in specs.iter() { - if level == Level::Forbid { - continue; - } - let forbid_src = match self.sets.get_lint_id_level(*id, self.cur, None) { - (Some(Level::Forbid), src) => src, - _ => continue, - }; - let forbidden_lint_name = match forbid_src { - LintSource::Default => id.to_string(), - LintSource::Node(name, _, _) => name.to_string(), - LintSource::CommandLine(name, _) => name.to_string(), - }; - let (lint_attr_name, lint_attr_span) = match *src { - LintSource::Node(name, span, _) => (name, span), - _ => continue, - }; - let mut diag_builder = struct_span_err!( - self.sess, - lint_attr_span, - E0453, - "{}({}) overruled by outer forbid({})", - level.as_str(), - lint_attr_name, - forbidden_lint_name - ); - diag_builder.span_label(lint_attr_span, "overruled by previous forbid"); - match forbid_src { - LintSource::Default => {} - LintSource::Node(_, forbid_source_span, reason) => { - diag_builder.span_label(forbid_source_span, "`forbid` level set here"); - if let Some(rationale) = reason { - diag_builder.note(&rationale.as_str()); - } - } - LintSource::CommandLine(_, _) => { - diag_builder.note("`forbid` lint level was set on command line"); - } - } - diag_builder.emit(); - // don't set a separate error for every lint in the group - break; - } - let prev = self.cur; if !specs.is_empty() { self.cur = self.sets.list.len() as u32; diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 81549be4b0915..80ef855c3859e 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -463,6 +463,8 @@ fn register_internals(store: &mut LintStore) { store.register_early_pass(|| box DefaultHashTypes::new()); store.register_lints(&LintPassImpl::get_lints()); store.register_early_pass(|| box LintPassImpl); + store.register_lints(&ExistingDocKeyword::get_lints()); + store.register_late_pass(|| box ExistingDocKeyword); store.register_lints(&TyTyKind::get_lints()); store.register_late_pass(|| box TyTyKind); store.register_group( @@ -475,6 +477,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), LintId::of(TY_PASS_BY_REFERENCE), LintId::of(USAGE_OF_QUALIFIED_TY), + LintId::of(EXISTING_DOC_KEYWORD), ], ); } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f53a40278062c..c571ed7b61262 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1592,23 +1592,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.def_path_hash_unlocked(index, &mut def_path_hashes) } - fn all_def_path_hashes_and_def_ids(&self) -> Vec<(DefPathHash, DefId)> { - let mut def_path_hashes = self.def_path_hash_cache.lock(); - let mut def_index_to_data = |index| { - (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index)) - }; - if let Some(data) = &self.root.proc_macro_data { - std::iter::once(CRATE_DEF_INDEX) - .chain(data.macros.decode(self)) - .map(def_index_to_data) - .collect() - } else { - (0..self.num_def_ids()) - .map(|index| def_index_to_data(DefIndex::from_usize(index))) - .collect() - } - } - /// Get the `DepNodeIndex` corresponding this crate. The result of this /// method is cached in the `dep_node_index` field. fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 2ffd239b2f06c..b7f2288521790 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -456,6 +456,10 @@ impl CStore { pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId { self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess) } + + pub fn num_def_ids(&self, cnum: CrateNum) -> usize { + self.get_crate_data(cnum).num_def_ids() + } } impl CrateStore for CStore { @@ -498,14 +502,6 @@ impl CrateStore for CStore { self.get_crate_data(def.krate).def_path_hash(def.index) } - fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)> { - self.get_crate_data(cnum).all_def_path_hashes_and_def_ids() - } - - fn num_def_ids(&self, cnum: CrateNum) -> usize { - self.get_crate_data(cnum).num_def_ids() - } - // See `CrateMetadataRef::def_path_hash_to_def_id` for more details fn def_path_hash_to_def_id( &self, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 672073b1d3472..9a42bbe7bacdd 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -32,6 +32,7 @@ macro_rules! arena_types { [decode] borrowck_result: rustc_middle::mir::BorrowCheckResult<$tcx>, [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, + [decode] code_region: rustc_middle::mir::coverage::CodeRegion, [] const_allocs: rustc_middle::mir::interpret::Allocation, // Required for the incremental on-disk cache [few] mir_keys: rustc_hir::def_id::DefIdSet, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 5e36362ec5916..598e28c1a3ab0 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -47,7 +47,7 @@ fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> { } } -fn fn_sig<'hir>(node: Node<'hir>) -> Option<&'hir FnSig<'hir>> { +pub fn fn_sig<'hir>(node: Node<'hir>) -> Option<&'hir FnSig<'hir>> { match &node { Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. }) | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. }) diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 5da4be4e98279..143b3867d9fc7 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -4,7 +4,18 @@ use crate::ty::Ty; use rustc_hir::HirId; use rustc_target::abi::VariantIdx; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + TypeFoldable, + HashStable +)] pub enum PlaceBase { /// A temporary variable Rvalue, @@ -16,7 +27,18 @@ pub enum PlaceBase { Upvar(ty::UpvarId), } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + TypeFoldable, + HashStable +)] pub enum ProjectionKind { /// A dereference of a pointer, reference or `Box` of the given type Deref, @@ -36,7 +58,18 @@ pub enum ProjectionKind { Subslice, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + TypeFoldable, + HashStable +)] pub struct Projection<'tcx> { /// Type after the projection is being applied. pub ty: Ty<'tcx>, @@ -48,7 +81,7 @@ pub struct Projection<'tcx> { /// A `Place` represents how a value is located in memory. /// /// This is an HIR version of `mir::Place` -#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct Place<'tcx> { /// The type of the `PlaceBase` pub base_ty: Ty<'tcx>, @@ -61,7 +94,7 @@ pub struct Place<'tcx> { /// A `PlaceWithHirId` represents how a value is located in memory. /// /// This is an HIR version of `mir::Place` -#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct PlaceWithHirId<'tcx> { /// `HirId` of the expression or pattern producing this value. pub hir_id: HirId, diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index bd7121ca1d70f..6d2c43874bc0f 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -189,8 +189,6 @@ pub trait CrateStore { fn def_kind(&self, def: DefId) -> DefKind; fn def_path(&self, def: DefId) -> DefPath; fn def_path_hash(&self, def: DefId) -> DefPathHash; - fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)>; - fn num_def_ids(&self, cnum: CrateNum) -> usize; fn def_path_hash_to_def_id( &self, cnum: CrateNum, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b516810205fef..1b5f7a2c12e72 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -346,6 +346,21 @@ rustc_queries! { cache_on_disk_if { key.is_local() } } + /// Returns the name of the file that contains the function body, if instrumented for coverage. + query covered_file_name(key: DefId) -> Option { + desc { |tcx| "retrieving the covered file name, if instrumented, for `{}`", tcx.def_path_str(key) } + storage(ArenaCacheSelector<'tcx>) + cache_on_disk_if { key.is_local() } + } + + /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the + /// function was optimized out before codegen, and before being added to the Coverage Map. + query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> { + desc { |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`", tcx.def_path_str(key) } + storage(ArenaCacheSelector<'tcx>) + cache_on_disk_if { key.is_local() } + } + /// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own /// `DefId`. This function returns all promoteds in the specified body. The body references /// promoteds by the `DefId` and the `mir::Promoted` index. This is necessary, because @@ -433,23 +448,12 @@ rustc_queries! { /// full predicates are available (note that supertraits have /// additional acyclicity requirements). query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) } - } - - /// The `Option` is the name of an associated type. If it is `None`, then this query - /// returns the full set of predicates. If `Some`, then the query returns only the - /// subset of super-predicates that reference traits that define the given associated type. - /// This is used to avoid cycles in resolving types like `T::Item`. - query super_predicates_that_define_assoc_type(key: (DefId, Option)) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the super traits of `{}`{}", - tcx.def_path_str(key.0), - if let Some(assoc_name) = key.1 { format!(" with associated type name `{}`", assoc_name) } else { "".to_string() }, - } + desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) } } /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. - query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { + query type_param_predicates(key: (DefId, LocalDefId)) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the bounds for type parameter `{}`", { let id = tcx.hir().local_def_id_to_hir_id(key.1); tcx.hir().ty_param_name(id) diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 1def4936860f1..b2fc3710cd673 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -162,7 +162,8 @@ encodable_via_deref! { ty::Region<'tcx>, &'tcx mir::Body<'tcx>, &'tcx mir::UnsafetyCheckResult, - &'tcx mir::BorrowCheckResult<'tcx> + &'tcx mir::BorrowCheckResult<'tcx>, + &'tcx mir::coverage::CodeRegion } pub trait TyDecoder<'tcx>: Decoder { @@ -376,7 +377,8 @@ impl_decodable_via_ref! { &'tcx Allocation, &'tcx mir::Body<'tcx>, &'tcx mir::UnsafetyCheckResult, - &'tcx mir::BorrowCheckResult<'tcx> + &'tcx mir::BorrowCheckResult<'tcx>, + &'tcx mir::coverage::CodeRegion } #[macro_export] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f078bbacfe96c..a8d007c0be27d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -51,7 +51,7 @@ use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; use rustc_session::Session; use rustc_span::source_map::MultiSpan; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; @@ -624,6 +624,19 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } } + /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured + /// by the closure. + pub fn closure_min_captures_flattened( + &self, + closure_def_id: DefId, + ) -> impl Iterator> { + self.closure_min_captures + .get(&closure_def_id) + .map(|closure_min_captures| closure_min_captures.values().flat_map(|v| v.iter())) + .into_iter() + .flatten() + } + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> { self.upvar_capture_map[&upvar_id] } @@ -2066,42 +2079,6 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig })) } - /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` - /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. - pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool { - self.super_traits_of(trait_def_id).any(|trait_did| { - self.associated_items(trait_did) - .find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, trait_did) - .is_some() - }) - } - - /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally) - /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used - /// to identify which traits may define a given associated type to help avoid cycle errors. - /// Returns a `DefId` iterator. - fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator + 'tcx { - let mut set = FxHashSet::default(); - let mut stack = vec![trait_def_id]; - - set.insert(trait_def_id); - - iter::from_fn(move || -> Option { - let trait_did = stack.pop()?; - let generic_predicates = self.super_predicates_of(trait_did); - - for (predicate, _) in generic_predicates.predicates { - if let ty::PredicateAtom::Trait(data, _) = predicate.skip_binders() { - if set.insert(data.def_id()) { - stack.push(data.def_id()); - } - } - } - - Some(trait_did) - }) - } - /// Given a closure signature, returns an equivalent fn signature. Detuples /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then /// you would get a `fn(u32, i32)`. diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 00fea91fdfcb8..d6b3afb3be3df 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2848,7 +2848,7 @@ where || abi == SpecAbi::RustIntrinsic || abi == SpecAbi::PlatformIntrinsic { - let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, is_ret: bool| { + let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>| { if arg.is_ignore() { return; } @@ -2886,9 +2886,9 @@ where _ => return, } - // Return structures up to 2 pointers in size by value, matching `ScalarPair`. LLVM - // will usually return these in 2 registers, which is more efficient than by-ref. - let max_by_val_size = if is_ret { Pointer.size(cx) * 2 } else { Pointer.size(cx) }; + // Pass and return structures up to 2 pointers in size by value, matching `ScalarPair`. + // LLVM will usually pass these in 2 registers, which is more efficient than by-ref. + let max_by_val_size = Pointer.size(cx) * 2; let size = arg.layout.size; if arg.layout.is_unsized() || size > max_by_val_size { @@ -2900,9 +2900,9 @@ where arg.cast_to(Reg { kind: RegKind::Integer, size }); } }; - fixup(&mut self.ret, true); + fixup(&mut self.ret); for arg in &mut self.args { - fixup(arg, false); + fixup(arg); } return; } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5d8edcf70bfd3..1a9a6a33fefd4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -672,7 +672,18 @@ impl<'a, 'tcx> HashStable> for TyS<'tcx> { #[rustc_diagnostic_item = "Ty"] pub type Ty<'tcx> = &'tcx TyS<'tcx>; -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + TypeFoldable, + HashStable +)] pub struct UpvarPath { pub hir_id: hir::HirId, } @@ -680,7 +691,7 @@ pub struct UpvarPath { /// Upvars do not get their own `NodeId`. Instead, we use the pair of /// the original var ID (that is, the root variable that is referenced /// by the upvar) and the ID of the closure expression. -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct UpvarId { pub var_path: UpvarPath, pub closure_expr_id: LocalDefId, @@ -692,7 +703,7 @@ impl UpvarId { } } -#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)] +#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, TypeFoldable, Copy, HashStable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. ImmBorrow, @@ -746,7 +757,7 @@ pub enum BorrowKind { /// Information describing the capture of an upvar. This is computed /// during `typeck`, specifically by `regionck`. -#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub enum UpvarCapture<'tcx> { /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases @@ -763,7 +774,7 @@ pub enum UpvarCapture<'tcx> { ByRef(UpvarBorrow<'tcx>), } -#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct UpvarBorrow<'tcx> { /// The kind of borrow: by-ref upvars have access to shared /// immutable borrows, which are not part of the normal language @@ -790,7 +801,7 @@ pub type RootVariableMinCaptureList<'tcx> = FxIndexMap = Vec>; /// A `Place` and the corresponding `CaptureInfo`. -#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct CapturedPlace<'tcx> { pub place: HirPlace<'tcx>, pub info: CaptureInfo<'tcx>, @@ -799,7 +810,7 @@ pub struct CapturedPlace<'tcx> { /// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move) /// for a particular capture as well as identifying the part of the source code /// that triggered this capture to occur. -#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct CaptureInfo<'tcx> { /// Expr Id pointing to use that resulted in selecting the current capture kind /// diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs index 3949c303f727a..a005990264cf1 100644 --- a/compiler/rustc_middle/src/ty/query/keys.rs +++ b/compiler/rustc_middle/src/ty/query/keys.rs @@ -7,7 +7,7 @@ use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::{self, Ty, TyCtxt}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_query_system::query::DefaultCacheSelector; -use rustc_span::symbol::{Ident, Symbol}; +use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; /// The `Key` trait controls what types can legally be used as the key @@ -149,28 +149,6 @@ impl Key for (LocalDefId, DefId) { } } -impl Key for (DefId, Option) { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.0.krate - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - tcx.def_span(self.0) - } -} - -impl Key for (DefId, LocalDefId, Ident) { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.0.krate - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - self.1.default_span(tcx) - } -} - impl Key for (CrateNum, DefId) { type CacheSelector = DefaultCacheSelector; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 78994c6e1c77a..a90807de99d3e 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2174,6 +2174,15 @@ impl<'tcx> TyS<'tcx> { } } + /// Get the `i`-th element of a tuple. + /// Panics when called on anything but a tuple. + pub fn tuple_element_ty(&self, i: usize) -> Option> { + match self.kind() { + Tuple(substs) => substs.iter().nth(i).map(|field| field.expect_ty()), + _ => bug!("tuple_fields called on non-tuple"), + } + } + /// If the type contains variants, returns the valid range of variant indices. // // FIXME: This requires the optimized MIR in the case of generators. diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index e23c3f5196709..25787f005aa23 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -18,7 +18,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, TargetDataLayout}; use smallvec::SmallVec; use std::{cmp, fmt}; @@ -221,7 +221,13 @@ impl<'tcx> TyCtxt<'tcx> { mut ty: Ty<'tcx>, normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>, ) -> Ty<'tcx> { - loop { + for iteration in 0.. { + if !self.sess.recursion_limit().value_within_limit(iteration) { + return self.ty_error_with_message( + DUMMY_SP, + &format!("reached the recursion limit finding the struct tail for {}", ty), + ); + } match *ty.kind() { ty::Adt(def, substs) => { if !def.is_struct() { diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index de54c5582e049..80eabdd9af830 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -9,6 +9,7 @@ use rustc_hir::{HirId, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::mir::{ traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem, PlaceRef, @@ -75,6 +76,7 @@ crate use region_infer::RegionInferenceContext; crate struct Upvar { name: Symbol, + // FIXME(project-rfc-2229#8): This should use Place or something similar var_hir_id: HirId, /// If true, the capture is behind a reference. @@ -155,13 +157,13 @@ fn do_mir_borrowck<'a, 'tcx>( infcx.set_tainted_by_errors(); } let upvars: Vec<_> = tables - .closure_captures - .get(&def.did.to_def_id()) - .into_iter() - .flat_map(|v| v.values()) - .map(|upvar_id| { - let var_hir_id = upvar_id.var_path.hir_id; - let capture = tables.upvar_capture(*upvar_id); + .closure_min_captures_flattened(def.did.to_def_id()) + .map(|captured_place| { + let var_hir_id = match captured_place.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + _ => bug!("Expected upvar"), + }; + let capture = captured_place.info.capture_kind; let by_ref = match capture { ty::UpvarCapture::ByValue(_) => false, ty::UpvarCapture::ByRef(..) => true, diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index a5c45452dec85..543b7e7ebaa79 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -749,7 +749,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { (&adt_def.variants[VariantIdx::new(0)], substs) } ty::Closure(_, substs) => { - return match substs.as_closure().upvar_tys().nth(field.index()) { + return match substs + .as_closure() + .tupled_upvars_ty() + .tuple_element_ty(field.index()) + { Some(ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { field_count: substs.as_closure().upvar_tys().count(), diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index c72089ec55a99..187f6fab5181f 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -1,17 +1,20 @@ use rustc_middle::mir; use rustc_middle::ty::layout::HasTyCtxt; +use rustc_middle::ty::InstanceDef; use rustc_middle::ty::{self, Ty}; use std::borrow::Borrow; use std::collections::hash_map::Entry; use std::hash::Hash; use rustc_data_structures::fx::FxHashMap; +use std::fmt; use rustc_ast::Mutability; use rustc_hir::def_id::DefId; use rustc_middle::mir::AssertMessage; use rustc_session::Limit; use rustc_span::symbol::{sym, Symbol}; +use rustc_target::abi::{Align, Size}; use crate::interpret::{ self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx, @@ -37,6 +40,14 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { if instance.def.requires_caller_location(self.tcx()) { return Ok(false); } + // Only memoize instrinsics. This was added in #79594 while adding the `const_allocate` intrinsic. + // We only memoize intrinsics because it would be unsound to memoize functions + // which might interact with the heap. + // Additionally, const_allocate intrinsic is impure and thus should not be memoized; + // it will not be memoized because it has non-ZST args + if !matches!(instance.def, InstanceDef::Intrinsic(_)) { + return Ok(false); + } // For the moment we only do this for functions which take no arguments // (or all arguments are ZSTs) so that we don't memoize too much. if args.iter().any(|a| !a.layout.is_zst()) { @@ -169,6 +180,28 @@ impl interpret::AllocMap for FxHashMap { crate type CompileTimeEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>; +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum MemoryKind { + Heap, +} + +impl fmt::Display for MemoryKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MemoryKind::Heap => write!(f, "heap allocation"), + } + } +} + +impl interpret::MayLeak for MemoryKind { + #[inline(always)] + fn may_leak(self) -> bool { + match self { + MemoryKind::Heap => false, + } + } +} + impl interpret::MayLeak for ! { #[inline(always)] fn may_leak(self) -> bool { @@ -212,6 +245,8 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> { compile_time_machine!(<'mir, 'tcx>); + type MemoryKind = MemoryKind; + type MemoryExtra = MemoryExtra; fn find_mir_or_eval_fn( @@ -295,6 +330,22 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, }; ecx.write_scalar(Scalar::from_bool(cmp), dest)?; } + sym::const_allocate => { + let size = ecx.read_scalar(args[0])?.to_machine_usize(ecx)?; + let align = ecx.read_scalar(args[1])?.to_machine_usize(ecx)?; + + let align = match Align::from_bytes(align) { + Ok(a) => a, + Err(err) => throw_ub_format!("align has to be a power of 2, {}", err), + }; + + let ptr = ecx.memory.allocate( + Size::from_bytes(size as u64), + align, + interpret::MemoryKind::Machine(MemoryKind::Heap), + ); + ecx.write_scalar(Scalar::Ptr(ptr), dest)?; + } _ => { return Err(ConstEvalErrKind::NeedsRfc(format!( "calling intrinsic `{}`", diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index 413be427339f3..01d58c47e3ab9 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -25,19 +25,20 @@ use rustc_target::abi::Size; use rustc_ast::Mutability; use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, Scalar, ValueVisitor}; +use crate::const_eval; -pub trait CompileTimeMachine<'mir, 'tcx> = Machine< +pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine< 'mir, 'tcx, - MemoryKind = !, + MemoryKind = T, PointerTag = (), ExtraFnVal = !, FrameExtra = (), AllocExtra = (), - MemoryMap = FxHashMap, Allocation)>, + MemoryMap = FxHashMap, Allocation)>, >; -struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> { +struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> { /// The ectx from which we intern. ecx: &'rt mut InterpCx<'mir, 'tcx, M>, /// Previously encountered safe references. @@ -74,7 +75,7 @@ struct IsStaticOrFn; /// `immutable` things might become mutable if `ty` is not frozen. /// `ty` can be `None` if there is no potential interior mutability /// to account for (e.g. for vtables). -fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( +fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>( ecx: &'rt mut InterpCx<'mir, 'tcx, M>, leftover_allocations: &'rt mut FxHashSet, alloc_id: AllocId, @@ -104,7 +105,10 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( // This match is just a canary for future changes to `MemoryKind`, which most likely need // changes in this function. match kind { - MemoryKind::Stack | MemoryKind::Vtable | MemoryKind::CallerLocation => {} + MemoryKind::Stack + | MemoryKind::Machine(const_eval::MemoryKind::Heap) + | MemoryKind::Vtable + | MemoryKind::CallerLocation => {} } // Set allocation mutability as appropriate. This is used by LLVM to put things into // read-only memory, and also by Miri when evaluating other globals that @@ -138,7 +142,9 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( None } -impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir, 'tcx, M> { +impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> + InternVisitor<'rt, 'mir, 'tcx, M> +{ fn intern_shallow( &mut self, alloc_id: AllocId, @@ -149,8 +155,8 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir } } -impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> - for InternVisitor<'rt, 'mir, 'tcx, M> +impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> + ValueVisitor<'mir, 'tcx, M> for InternVisitor<'rt, 'mir, 'tcx, M> { type V = MPlaceTy<'tcx>; @@ -287,7 +293,7 @@ pub enum InternKind { /// Any errors here would anyway be turned into `const_err` lints, whereas validation failures /// are hard errors. #[tracing::instrument(skip(ecx))] -pub fn intern_const_alloc_recursive>( +pub fn intern_const_alloc_recursive>( ecx: &mut InterpCx<'mir, 'tcx, M>, intern_kind: InternKind, ret: MPlaceTy<'tcx>, @@ -418,7 +424,9 @@ where Ok(()) } -impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> + InterpCx<'mir, 'tcx, M> +{ /// A helper function that allocates memory for the layout given and gives you access to mutate /// it. Once your own mutation code is done, the backing `Allocation` is removed from the /// current `Memory` and returned. diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 66dbacb2f9d4d..0bba027377229 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -366,9 +366,9 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { type PointerTag = (); type ExtraFnVal = !; - type MemoryKind = !; - type MemoryMap = rustc_data_structures::fx::FxHashMap, Allocation)>; - const GLOBAL_KIND: Option = None; // no copying of globals from `tcx` to machine memory + type MemoryMap = + rustc_data_structures::fx::FxHashMap, Allocation)>; + const GLOBAL_KIND: Option = None; // no copying of globals from `tcx` to machine memory type AllocExtra = (); type FrameExtra = (); @@ -407,7 +407,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { _memory_extra: &Self::MemoryExtra, _id: AllocId, alloc: Cow<'b, Allocation>, - _kind: Option>, + _kind: Option>, ) -> (Cow<'b, Allocation>, Self::PointerTag) { // We do not use a tag so we can just cheaply forward the allocation (alloc, ()) diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index abcf1862fd873..1d949e020ed5c 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -180,6 +180,8 @@ impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> { impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> { compile_time_machine!(<'mir, 'tcx>); + type MemoryKind = !; + type MemoryExtra = (); fn find_mir_or_eval_fn( diff --git a/compiler/rustc_mir/src/transform/coverage/graph.rs b/compiler/rustc_mir/src/transform/coverage/graph.rs index 9d375633dcf51..f79f0d3253899 100644 --- a/compiler/rustc_mir/src/transform/coverage/graph.rs +++ b/compiler/rustc_mir/src/transform/coverage/graph.rs @@ -118,18 +118,8 @@ impl CoverageGraph { match term.kind { TerminatorKind::Return { .. } - // FIXME(richkadel): Add test(s) for `Abort` coverage. | TerminatorKind::Abort - // FIXME(richkadel): Add test(s) for `Assert` coverage. - // Should `Assert` be handled like `FalseUnwind` instead? Since we filter out unwind - // branches when creating the BCB CFG, aren't `Assert`s (without unwinds) just like - // `FalseUnwinds` (which are kind of like `Goto`s)? - | TerminatorKind::Assert { .. } - // FIXME(richkadel): Add test(s) for `Yield` coverage, and confirm coverage is - // sensible for code using the `yield` keyword. | TerminatorKind::Yield { .. } - // FIXME(richkadel): Also add coverage tests using async/await, and threading. - | TerminatorKind::SwitchInt { .. } => { // The `bb` has more than one _outgoing_ edge, or exits the function. Save the // current sequence of `basic_blocks` gathered to this point, as a new @@ -147,6 +137,16 @@ impl CoverageGraph { // `Terminator`s `successors()` list) checking the number of successors won't // work. } + + // The following `TerminatorKind`s are either not expected outside an unwind branch, + // or they should not (under normal circumstances) branch. Coverage graphs are + // simplified by assuring coverage results are accurate for program executions that + // don't panic. + // + // Programs that panic and unwind may record slightly inaccurate coverage results + // for a coverage region containing the `Terminator` that began the panic. This + // is as intended. (See Issue #78544 for a possible future option to support + // coverage in test programs that panic.) TerminatorKind::Goto { .. } | TerminatorKind::Resume | TerminatorKind::Unreachable @@ -154,6 +154,7 @@ impl CoverageGraph { | TerminatorKind::DropAndReplace { .. } | TerminatorKind::Call { .. } | TerminatorKind::GeneratorDrop + | TerminatorKind::Assert { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::InlineAsm { .. } => {} @@ -278,6 +279,7 @@ rustc_index::newtype_index! { /// A node in the [control-flow graph][CFG] of CoverageGraph. pub(super) struct BasicCoverageBlock { DEBUG_FORMAT = "bcb{}", + const START_BCB = 0, } } diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index 192bb6680e420..10f522d67465d 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -88,6 +88,7 @@ struct Instrumentor<'a, 'tcx> { pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>, + fn_sig_span: Span, body_span: Span, basic_coverage_blocks: CoverageGraph, coverage_counters: CoverageCounters, @@ -95,14 +96,19 @@ struct Instrumentor<'a, 'tcx> { impl<'a, 'tcx> Instrumentor<'a, 'tcx> { fn new(pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self { - let hir_body = hir_body(tcx, mir_body.source.def_id()); + let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, mir_body.source.def_id()); let body_span = hir_body.value.span; + let fn_sig_span = match some_fn_sig { + Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()), + None => body_span.shrink_to_lo(), + }; let function_source_hash = hash_mir_source(tcx, hir_body); let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); Self { pass_name, tcx, mir_body, + fn_sig_span, body_span, basic_coverage_blocks, coverage_counters: CoverageCounters::new(function_source_hash), @@ -114,9 +120,15 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let source_map = tcx.sess.source_map(); let mir_source = self.mir_body.source; let def_id = mir_source.def_id(); + let fn_sig_span = self.fn_sig_span; let body_span = self.body_span; - debug!("instrumenting {:?}, span: {}", def_id, source_map.span_to_string(body_span)); + debug!( + "instrumenting {:?}, fn sig span: {}, body span: {}", + def_id, + source_map.span_to_string(fn_sig_span), + source_map.span_to_string(body_span) + ); let mut graphviz_data = debug::GraphvizData::new(); let mut debug_used_expressions = debug::UsedExpressions::new(); @@ -138,6 +150,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { // Compute `CoverageSpan`s from the `CoverageGraph`. let coverage_spans = CoverageSpans::generate_coverage_spans( &self.mir_body, + fn_sig_span, body_span, &self.basic_coverage_blocks, ); @@ -272,47 +285,13 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { bug!("Every BasicCoverageBlock should have a Counter or Expression"); }; graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind); - // FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special - // cases? - let some_code_region = if self.is_code_region_redundant(bcb, span, body_span) { - None - } else { - Some(make_code_region(file_name, &source_file, span, body_span)) - }; - inject_statement(self.mir_body, counter_kind, self.bcb_last_bb(bcb), some_code_region); - } - } - - /// Returns true if the type of `BasicCoverageBlock` (specifically, it's `BasicBlock`s - /// `TerminatorKind`) with the given `Span` (relative to the `body_span`) is known to produce - /// a redundant coverage count. - /// - /// There is at least one case for this, and if it's not handled, the last line in a function - /// will be double-counted. - /// - /// If this method returns `true`, the counter (which other `Expressions` may depend on) is - /// still injected, but without an associated code region. - // FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special cases? - fn is_code_region_redundant( - &self, - bcb: BasicCoverageBlock, - span: Span, - body_span: Span, - ) -> bool { - if span.hi() == body_span.hi() { - // All functions execute a `Return`-terminated `BasicBlock`, regardless of how the - // function returns; but only some functions also _can_ return after a `Goto` block - // that ends on the closing brace of the function (with the `Return`). When this - // happens, the last character is counted 2 (or possibly more) times, when we know - // the function returned only once (of course). By giving all `Goto` terminators at - // the end of a function a `non-reportable` code region, they are still counted - // if appropriate, but they don't increment the line counter, as long as their is - // also a `Return` on that last line. - if let TerminatorKind::Goto { .. } = self.bcb_terminator(bcb).kind { - return true; - } + inject_statement( + self.mir_body, + counter_kind, + self.bcb_last_bb(bcb), + Some(make_code_region(file_name, &source_file, span, body_span)), + ); } - false } /// `inject_coverage_span_counters()` looped through the `CoverageSpan`s and injected the @@ -411,11 +390,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { self.bcb_data(bcb).last_bb() } - #[inline] - fn bcb_terminator(&self, bcb: BasicCoverageBlock) -> &Terminator<'tcx> { - self.bcb_data(bcb).terminator(self.mir_body) - } - #[inline] fn bcb_data(&self, bcb: BasicCoverageBlock) -> &BasicCoverageBlockData { &self.basic_coverage_blocks[bcb] @@ -521,10 +495,15 @@ fn make_code_region( } } -fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { +fn fn_sig_and_body<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> (Option<&'tcx rustc_hir::FnSig<'tcx>>, &'tcx rustc_hir::Body<'tcx>) { + // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back + // to HIR for it. let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); - tcx.hir().body(fn_body_id) + (hir::map::fn_sig(hir_node), tcx.hir().body(fn_body_id)) } fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 { diff --git a/compiler/rustc_mir/src/transform/coverage/query.rs b/compiler/rustc_mir/src/transform/coverage/query.rs index e86bb96d29c30..aa34ae70ef1a4 100644 --- a/compiler/rustc_mir/src/transform/coverage/query.rs +++ b/compiler/rustc_mir/src/transform/coverage/query.rs @@ -1,6 +1,8 @@ +use super::*; + use rustc_middle::mir::coverage::*; use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Coverage, CoverageInfo, Location}; +use rustc_middle::mir::{self, Coverage, CoverageInfo, Location}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; @@ -9,6 +11,8 @@ use rustc_span::def_id::DefId; /// counter) and `FunctionCoverage::new()` (to extract the coverage map metadata from the MIR). pub(crate) fn provide(providers: &mut Providers) { providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id); + providers.covered_file_name = |tcx, def_id| covered_file_name(tcx, def_id); + providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id); } /// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in @@ -123,3 +127,34 @@ fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo coverage_visitor.info } + +fn covered_file_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option { + let mir_body = tcx.optimized_mir(def_id); + for bb_data in mir_body.basic_blocks().iter() { + for statement in bb_data.statements.iter() { + if let StatementKind::Coverage(box ref coverage) = statement.kind { + if let Some(code_region) = coverage.code_region.as_ref() { + return Some(code_region.file_name); + } + } + } + } + None +} + +fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> { + let mir_body: &'tcx mir::Body<'tcx> = tcx.optimized_mir(def_id); + mir_body + .basic_blocks() + .iter() + .map(|data| { + data.statements.iter().filter_map(|statement| match statement.kind { + StatementKind::Coverage(box ref coverage) => { + coverage.code_region.as_ref() // may be None + } + _ => None, + }) + }) + .flatten() + .collect() +} diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs index 95c49922262f6..6eb89754ee635 100644 --- a/compiler/rustc_mir/src/transform/coverage/spans.rs +++ b/compiler/rustc_mir/src/transform/coverage/spans.rs @@ -1,10 +1,9 @@ use super::debug::term_type; -use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; +use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB}; use crate::util::spanview::source_range_no_file; use rustc_data_structures::graph::WithNumNodes; -use rustc_index::bit_set::BitSet; use rustc_middle::mir::{ self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, @@ -74,6 +73,10 @@ pub(super) struct CoverageSpan { } impl CoverageSpan { + pub fn for_fn_sig(fn_sig_span: Span) -> Self { + Self { span: fn_sig_span, bcb: START_BCB, coverage_statements: vec![], is_closure: false } + } + pub fn for_statement( statement: &Statement<'tcx>, span: Span, @@ -82,10 +85,10 @@ impl CoverageSpan { stmt_index: usize, ) -> Self { let is_closure = match statement.kind { - StatementKind::Assign(box ( - _, - Rvalue::Aggregate(box AggregateKind::Closure(_, _), _), - )) => true, + StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => match kind { + AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _) => true, + _ => false, + }, _ => false, }; @@ -109,9 +112,6 @@ impl CoverageSpan { pub fn merge_from(&mut self, mut other: CoverageSpan) { debug_assert!(self.is_mergeable(&other)); self.span = self.span.to(other.span); - if other.is_closure { - self.is_closure = true; - } self.coverage_statements.append(&mut other.coverage_statements); } @@ -171,6 +171,9 @@ pub struct CoverageSpans<'a, 'tcx> { /// The MIR, used to look up `BasicBlockData`. mir_body: &'a mir::Body<'tcx>, + /// A `Span` covering the signature of function for the MIR. + fn_sig_span: Span, + /// A `Span` covering the function body of the MIR (typically from left curly brace to right /// curly brace). body_span: Span, @@ -216,11 +219,13 @@ pub struct CoverageSpans<'a, 'tcx> { impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { pub(super) fn generate_coverage_spans( mir_body: &'a mir::Body<'tcx>, + fn_sig_span: Span, body_span: Span, basic_coverage_blocks: &'a CoverageGraph, ) -> Vec { let mut coverage_spans = CoverageSpans { mir_body, + fn_sig_span, body_span, basic_coverage_blocks, sorted_spans_iter: None, @@ -277,6 +282,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { return initial_spans; } + initial_spans.push(CoverageSpan::for_fn_sig(self.fn_sig_span)); + initial_spans.sort_unstable_by(|a, b| { if a.span.lo() == b.span.lo() { if a.span.hi() == b.span.hi() { @@ -331,7 +338,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { prev={:?}", self.prev() ); - self.discard_curr(); + self.take_curr(); } else if self.curr().is_closure { self.carve_out_span_for_closure(); } else if self.prev_original_span == self.curr().span { @@ -345,28 +352,28 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { debug!(" AT END, adding last prev={:?}", self.prev()); let prev = self.take_prev(); - let CoverageSpans { - mir_body, basic_coverage_blocks, pending_dups, mut refined_spans, .. - } = self; + let CoverageSpans { pending_dups, mut refined_spans, .. } = self; for dup in pending_dups { debug!(" ...adding at least one pending dup={:?}", dup); refined_spans.push(dup); } - refined_spans.push(prev); - - // Remove `CoverageSpan`s with empty spans ONLY if the empty `CoverageSpan`s BCB also has at - // least one other non-empty `CoverageSpan`. - let mut has_coverage = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - for covspan in &refined_spans { - if !covspan.span.is_empty() { - has_coverage.insert(covspan.bcb); - } + + // Async functions wrap a closure that implements the body to be executed. The enclosing + // function is called and returns an `impl Future` without initially executing any of the + // body. To avoid showing the return from the enclosing function as a "covered" return from + // the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is + // excluded. The closure's `Return` is the only one that will be counted. This provides + // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace + // of the function body.) + let body_ends_with_closure = if let Some(last_covspan) = refined_spans.last() { + last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi() + } else { + false + }; + + if !body_ends_with_closure { + refined_spans.push(prev); } - refined_spans.retain(|covspan| { - !(covspan.span.is_empty() - && is_goto(&basic_coverage_blocks[covspan.bcb].terminator(mir_body).kind) - && has_coverage.contains(covspan.bcb)) - }); // Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage // regions for the current function leave room for the closure's own coverage regions @@ -491,8 +498,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the /// `curr` coverage span. - fn discard_curr(&mut self) { - self.some_curr = None; + fn take_curr(&mut self) -> CoverageSpan { + self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) } /// Returns true if the curr span should be skipped because prev has already advanced beyond the @@ -508,11 +515,11 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { self.prev().span.hi() <= self.curr().span.lo() } - /// If `prev`s span extends left of the closure (`curr`), carve out the closure's - /// span from `prev`'s span. (The closure's coverage counters will be injected when - /// processing the closure's own MIR.) Add the portion of the span to the left of the - /// closure; and if the span extends to the right of the closure, update `prev` to - /// that portion of the span. For any `pending_dups`, repeat the same process. + /// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from + /// `prev`'s span. (The closure's coverage counters will be injected when processing the + /// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span + /// extends to the right of the closure, update `prev` to that portion of the span. For any + /// `pending_dups`, repeat the same process. fn carve_out_span_for_closure(&mut self) { let curr_span = self.curr().span; let left_cutoff = curr_span.lo(); @@ -541,7 +548,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { dup.span = dup.span.with_lo(right_cutoff); } self.pending_dups.append(&mut pending_dups); - self.discard_curr(); // since self.prev() was already updated + let closure_covspan = self.take_curr(); + self.refined_spans.push(closure_covspan); // since self.prev() was already updated } else { pending_dups.clear(); } @@ -705,30 +713,8 @@ pub(super) fn filtered_terminator_span( | TerminatorKind::DropAndReplace { .. } | TerminatorKind::SwitchInt { .. } // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`. - // FIXME(richkadel): Note that `Goto` was moved to it's own match arm, for the reasons - // described below. Add tests to confirm whether or not similar cases also apply to - // `FalseEdge`. - | TerminatorKind::FalseEdge { .. } => None, - - // FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special cases? - // - // `Goto`s are often the targets of `SwitchInt` branches, and certain important - // optimizations to replace some `Counter`s with `Expression`s require a separate - // `BasicCoverageBlock` for each branch, to support the `Counter`, when needed. - // - // Also, some test cases showed that `Goto` terminators, and to some degree their `Span`s, - // provided useful context for coverage, such as to count and show when `if` blocks - // _without_ `else` blocks execute the `false` case (counting when the body of the `if` - // was _not_ taken). In these cases, the `Goto` span is ultimately given a `CoverageSpan` - // of 1 character, at the end of it's original `Span`. - // - // However, in other cases, a visible `CoverageSpan` is not wanted, but the `Goto` - // block must still be counted (for example, to contribute its count to an `Expression` - // that reports the execution count for some other block). In these cases, the code region - // is set to `None`. (See `Instrumentor::is_code_region_redundant()`.) - TerminatorKind::Goto { .. } => { - Some(function_source_span(terminator.source_info.span.shrink_to_hi(), body_span)) - } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::Goto { .. } => None, // Retain spans from all other terminators TerminatorKind::Resume @@ -749,11 +735,3 @@ fn function_source_span(span: Span, body_span: Span) -> Span { let span = original_sp(span, body_span).with_ctxt(SyntaxContext::root()); if body_span.contains(span) { span } else { body_span } } - -#[inline(always)] -fn is_goto(term_kind: &TerminatorKind<'tcx>) -> bool { - match term_kind { - TerminatorKind::Goto { .. } => true, - _ => false, - } -} diff --git a/compiler/rustc_mir/src/util/generic_graphviz.rs b/compiler/rustc_mir/src/util/generic_graphviz.rs index 8bd4a512bbb05..fd55a4dfc4c92 100644 --- a/compiler/rustc_mir/src/util/generic_graphviz.rs +++ b/compiler/rustc_mir/src/util/generic_graphviz.rs @@ -116,9 +116,13 @@ impl< write!(w, r#""#)?; - // FIXME(richkadel): Need generic way to know if node header should have a different color + // FIXME(richkadel): If/when migrating the MIR graphviz to this generic implementation, + // we need generic way to know if node header should have a different color. For example, + // for MIR: + // // let (blk, bgcolor) = if data.is_cleanup { - // (format!("{:?} (cleanup)", node), "lightblue") + // let color = if dark_mode { "royalblue" } else { "lightblue" }; + // (format!("{:?} (cleanup)", node), color) // } else { // let color = if dark_mode { "dimgray" } else { "gray" }; // (format!("{:?}", node), color) diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index d5f72e6f22dfa..82f38ac0e7620 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -3,6 +3,7 @@ use crate::build::ForGuard::OutsideGuard; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::thir::*; use rustc_hir as hir; +use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; use rustc_session::lint::Level; @@ -12,6 +13,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn ast_block( &mut self, destination: Place<'tcx>, + scope: Option, block: BasicBlock, ast_block: &'tcx hir::Block<'tcx>, source_info: SourceInfo, @@ -28,9 +30,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| { this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| { if targeted_by_break { - this.in_breakable_scope(None, destination, span, |this| { + this.in_breakable_scope(None, destination, scope, span, |this| { Some(this.ast_block_stmts( destination, + scope, block, span, stmts, @@ -39,7 +42,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { )) }) } else { - this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode) + this.ast_block_stmts(destination, scope, block, span, stmts, expr, safety_mode) } }) }) @@ -48,6 +51,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn ast_block_stmts( &mut self, destination: Place<'tcx>, + scope: Option, mut block: BasicBlock, span: Span, stmts: Vec>, @@ -182,7 +186,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored, span }); - unpack!(block = this.into(destination, block, expr)); + unpack!(block = this.into(destination, scope, block, expr)); let popped = this.block_context.pop(); assert!(popped.map_or(false, |bf| bf.is_tail_expr())); diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index e6263e5d6cf9b..e1a3dc87c8c8d 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -4,14 +4,62 @@ use crate::build::expr::category::Category; use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::thir::*; +use rustc_hir::def_id::DefId; +use rustc_hir::HirId; use rustc_middle::middle::region; +use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance}; use rustc_span::Span; +use rustc_target::abi::VariantIdx; use rustc_index::vec::Idx; +/// The "outermost" place that holds this value. +#[derive(Copy, Clone)] +crate enum PlaceBase { + /// Denotes the start of a `Place`. + Local(Local), + + /// When building place for an expression within a closure, the place might start off a + /// captured path. When `capture_disjoint_fields` is enabled, we might not know the capture + /// index (within the desugared closure) of the captured path until most of the projections + /// are applied. We use `PlaceBase::Upvar` to keep track of the root variable off of which the + /// captured path starts, the closure the capture belongs to and the trait the closure + /// implements. + /// + /// Once we have figured out the capture index, we can convert the place builder to start from + /// `PlaceBase::Local`. + /// + /// Consider the following example + /// ```rust + /// let t = (10, (10, (10, 10))); + /// + /// let c = || { + /// println!("{}", t.0.0.0); + /// }; + /// ``` + /// Here the THIR expression for `t.0.0.0` will be something like + /// + /// ``` + /// * Field(0) + /// * Field(0) + /// * Field(0) + /// * UpvarRef(t) + /// ``` + /// + /// When `capture_disjoint_fields` is enabled, `t.0.0.0` is captured and we won't be able to + /// figure out that it is captured until all the `Field` projections are applied. + Upvar { + /// HirId of the upvar + var_hir_id: HirId, + /// DefId of the closure + closure_def_id: DefId, + /// The trait closure implements, `Fn`, `FnMut`, `FnOnce` + closure_kind: ty::ClosureKind }, +} + /// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a /// place by pushing more and more projections onto the end, and then convert the final set into a /// place using the `into_place` method. @@ -19,14 +67,240 @@ use rustc_index::vec::Idx; /// This is used internally when building a place for an expression like `a.b.c`. The fields `b` /// and `c` can be progressively pushed onto the place builder that is created when converting `a`. #[derive(Clone)] -struct PlaceBuilder<'tcx> { - local: Local, +crate struct PlaceBuilder<'tcx> { + base: PlaceBase, projection: Vec>, } +/// Given a list of MIR projections, convert them to list of HIR ProjectionKind. +/// The projections are truncated to represent a path that might be captured by a +/// closure/generator. This implies the vector returned from this function doesn't contain +/// ProjectionElems `Downcast`, `ConstantIndex`, `Index`, or `Subslice` because those will never be +/// part of a path that is captued by a closure. We stop applying projections once we see the first +/// projection that isn't captured by a closure. +fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( + mir_projections: &Vec>, +) -> Vec { + + let mut hir_projections = Vec::new(); + + for mir_projection in mir_projections { + let hir_projection = match mir_projection { + ProjectionElem::Deref => HirProjectionKind::Deref, + ProjectionElem::Field(field, _) => { + // We will never encouter this for multivariant enums, + // read the comment for `Downcast`. + HirProjectionKind::Field(field.index() as u32, VariantIdx::new(0)) + }, + ProjectionElem::Downcast(..) => { + // This projections exist only for enums that have + // multiple variants. Since such enums that are captured + // completely, we can stop here. + break + }, + ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => { + // We don't capture array-access projections. + // We can stop here as arrays are captured completely. + break + }, + }; + + hir_projections.push(hir_projection); + } + + hir_projections +} + +/// Return true if the `proj_possible_ancestor` represents an ancestor path +/// to `proj_capture` or `proj_possible_ancestor` is same as `proj_capture`, +/// assuming they both start off of the same root variable. +/// +/// **Note:** It's the caller's responsibility to ensure that both lists of projections +/// start off of the same root variable. +/// +/// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of +/// `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`. +/// Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`. +/// 2. Since we only look at the projections here function will return `bar.x` as an a valid +/// ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections +/// list are being applied to the same root variable. +fn is_ancestor_or_same_capture( + proj_possible_ancestor: &Vec, + proj_capture: &Vec, +) -> bool { + // We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false. + // Therefore we can't just check if all projections are same in the zipped iterator below. + if proj_possible_ancestor.len() > proj_capture.len() { + return false; + } + + proj_possible_ancestor.iter().zip(proj_capture).all(|(a, b)| a == b) +} + +/// Computes the index of a capture within the desugared closure provided the closure's +/// `closure_min_captures` and the capture's index of the capture in the +/// `ty::MinCaptureList` of the root variable `var_hir_id`. +fn compute_capture_idx<'tcx>( + closure_min_captures: &ty::RootVariableMinCaptureList<'tcx>, + var_hir_id: HirId, + root_var_idx: usize, +) -> usize { + let mut res = 0; + for (var_id, capture_list) in closure_min_captures { + if *var_id == var_hir_id { + res += root_var_idx; + break; + } else { + res += capture_list.len(); + } + } + + res +} + +/// Given a closure, returns the index of a capture within the desugared closure struct and the +/// `ty::CapturedPlace` which is the ancestor of the Place represented using the `var_hir_id` +/// and `projection`. +/// +/// Note there will be at most one ancestor for any given Place. +/// +/// Returns None, when the ancestor is not found. +fn find_capture_matching_projections<'a, 'tcx>( + typeck_results: &'a ty::TypeckResults<'tcx>, + var_hir_id: HirId, + closure_def_id: DefId, + projections: &Vec>, +) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> { + let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?; + let root_variable_min_captures = closure_min_captures.get(&var_hir_id)?; + + let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections); + + // If an ancestor is found, `idx` is the index within the list of captured places + // for root variable `var_hir_id` and `capture` is the `ty::CapturedPlace` itself. + let (idx, capture) = root_variable_min_captures.iter().enumerate().find(|(_, capture)| { + let possible_ancestor_proj_kinds = + capture.place.projections.iter().map(|proj| proj.kind).collect(); + is_ancestor_or_same_capture(&possible_ancestor_proj_kinds, &hir_projections) + })?; + + // Convert index to be from the presepective of the entire closure_min_captures map + // instead of just the root variable capture list + Some((compute_capture_idx(closure_min_captures, var_hir_id, idx), capture)) +} + +/// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the +/// `PlaceBuilder` now starts from `PlaceBase::Local`. +/// +/// Returns a Result with the error being the HirId of the Upvar that was not found. +fn to_upvars_resolved_place_builder<'a, 'tcx>( + from_builder: PlaceBuilder<'tcx>, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, +) -> Result, HirId> { + match from_builder.base { + PlaceBase::Local(_) => Ok(from_builder), + PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => { + // Captures are represented using fields inside a structure. + // This represents accessing self in the closure structure + let mut upvar_resolved_place_builder = PlaceBuilder::from(Local::new(1)); + match closure_kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { + upvar_resolved_place_builder = upvar_resolved_place_builder.deref(); + } + ty::ClosureKind::FnOnce => {} + } + + let (capture_index, capture) = + if let Some(capture_details) = find_capture_matching_projections( + typeck_results, + var_hir_id, + closure_def_id, + &from_builder.projection, + ) { + capture_details + } else { + if !tcx.features().capture_disjoint_fields { + bug!( + "No associated capture found for {:?}[{:#?}] even though \ + capture_disjoint_fields isn't enabled", + var_hir_id, + from_builder.projection + ) + } else { + // FIXME(project-rfc-2229#24): Handle this case properly + debug!( + "No associated capture found for {:?}[{:#?}]", + var_hir_id, + from_builder.projection, + ); + } + return Err(var_hir_id); + }; + + let closure_ty = + typeck_results.node_type(tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local())); + + let substs = match closure_ty.kind() { + ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), + ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), + _ => bug!("Lowering capture for non-closure type {:?}", closure_ty), + }; + + // Access the capture by accessing the field within the Closure struct. + // + // We must have inferred the capture types since we are building MIR, therefore + // it's safe to call `tuple_element_ty` and we can unwrap here because + // we know that the capture exists and is the `capture_index`-th capture. + let var_ty = substs.tupled_upvars_ty().tuple_element_ty(capture_index).unwrap(); + + upvar_resolved_place_builder = upvar_resolved_place_builder.field(Field::new(capture_index), var_ty); + + // If the variable is captured via ByRef(Immutable/Mutable) Borrow, + // we need to deref it + upvar_resolved_place_builder = match capture.info.capture_kind { + ty::UpvarCapture::ByRef(_) => upvar_resolved_place_builder.deref(), + ty::UpvarCapture::ByValue(_) => upvar_resolved_place_builder, + }; + + let next_projection = capture.place.projections.len(); + let mut curr_projections = from_builder.projection; + + // We used some of the projections to build the capture itself, + // now we apply the remaining to the upvar resolved place. + upvar_resolved_place_builder.projection.extend( + curr_projections.drain(next_projection..)); + + Ok(upvar_resolved_place_builder) + } + } +} + impl<'tcx> PlaceBuilder<'tcx> { - fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> { - Place { local: self.local, projection: tcx.intern_place_elems(&self.projection) } + crate fn into_place<'a>( + self, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, + ) -> Place<'tcx> { + if let PlaceBase::Local(local) = self.base { + Place { local, projection: tcx.intern_place_elems(&self.projection) } + } else { + self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results) + } + } + + fn expect_upvars_resolved<'a>( + self, + tcx: TyCtxt<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, + ) -> PlaceBuilder<'tcx> { + to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap() + } + + crate fn base(&self) -> PlaceBase { + self.base } fn field(self, f: Field, ty: Ty<'tcx>) -> Self { @@ -49,7 +323,13 @@ impl<'tcx> PlaceBuilder<'tcx> { impl<'tcx> From for PlaceBuilder<'tcx> { fn from(local: Local) -> Self { - Self { local, projection: Vec::new() } + Self { base: PlaceBase::Local(local), projection: Vec::new() } + } +} + +impl<'tcx> From for PlaceBuilder<'tcx> { + fn from(base: PlaceBase) -> Self { + Self { base, projection: Vec::new() } } } @@ -71,12 +351,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let place_builder = unpack!(block = self.as_place_builder(block, expr)); - block.and(place_builder.into_place(self.hir.tcx())) + block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results())) } /// This is used when constructing a compound `Place`, so that we can avoid creating /// intermediate `Place` values until we know the full set of projections. - fn as_place_builder(&mut self, block: BasicBlock, expr: M) -> BlockAnd> + crate fn as_place_builder(&mut self, block: BasicBlock, expr: M) -> BlockAnd> where M: Mirror<'tcx, Output = Expr<'tcx>>, { @@ -98,7 +378,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); - block.and(place_builder.into_place(self.hir.tcx())) + block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results())) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -161,27 +441,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, ), ExprKind::UpvarRef { closure_def_id, var_hir_id } => { - let capture = this - .hir - .typeck_results - .closure_captures - .get(&closure_def_id) - .and_then(|captures| captures.get_full(&var_hir_id)); - - if capture.is_none() { - if !this.hir.tcx().features().capture_disjoint_fields { - bug!( - "No associated capture found for {:?} even though \ - capture_disjoint_fields isn't enabled", - expr.kind - ) - } - // FIXME(project-rfc-2229#24): Handle this case properly - } - - // Unwrap until the FIXME has been resolved - let (capture_index, _, upvar_id) = capture.unwrap(); - this.lower_closure_capture(block, capture_index, *upvar_id) + let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local()); + this.lower_captured_upvar(block, upvar_id) } ExprKind::VarRef { id } => { @@ -208,7 +469,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: expr.ty, }); - let place = place_builder.clone().into_place(this.hir.tcx()); + let place = + place_builder.clone().into_place(this.hir.tcx(), this.hir.typeck_results()); this.cfg.push( block, Statement { @@ -293,59 +555,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - /// Lower a closure/generator capture by representing it as a field - /// access within the desugared closure/generator. - /// - /// `capture_index` is the index of the capture within the desugared - /// closure/generator. - fn lower_closure_capture( + /// Lower a captured upvar. Note we might not know the actual capture index, + /// so we create a place starting from `PlaceBase::Upvar`, which will be resolved + /// once all projections that allow us to indentify a capture have been applied. + fn lower_captured_upvar( &mut self, block: BasicBlock, - capture_index: usize, upvar_id: ty::UpvarId, - ) -> BlockAnd> { + ) -> BlockAnd> { let closure_ty = self .hir .typeck_results() .node_type(self.hir.tcx().hir().local_def_id_to_hir_id(upvar_id.closure_expr_id)); - // Captures are represented using fields inside a structure. - // This represents accessing self in the closure structure - let mut place_builder = PlaceBuilder::from(Local::new(1)); - - // In case of Fn/FnMut closures we must deref to access the fields - // Generators are considered FnOnce, so we ignore this step for them. - if let ty::Closure(_, closure_substs) = closure_ty.kind() { - match self.hir.infcx().closure_kind(closure_substs).unwrap() { - ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { - place_builder = place_builder.deref(); - } - ty::ClosureKind::FnOnce => {} - } - } - - let substs = match closure_ty.kind() { - ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), - ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), - _ => bug!("Lowering capture for non-closure type {:?}", closure_ty) + let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() { + self.hir.infcx().closure_kind(closure_substs).unwrap() + } else { + // Generators are considered FnOnce. + ty::ClosureKind::FnOnce }; - // Access the capture by accessing the field within the Closure struct. - // - // We must have inferred the capture types since we are building MIR, therefore - // it's safe to call `upvar_tys` and we can unwrap here because - // we know that the capture exists and is the `capture_index`-th capture. - let var_ty = substs.upvar_tys().nth(capture_index).unwrap(); - place_builder = place_builder.field(Field::new(capture_index), var_ty); - - // If the variable is captured via ByRef(Immutable/Mutable) Borrow, - // we need to deref it - match self.hir.typeck_results.upvar_capture(upvar_id) { - ty::UpvarCapture::ByRef(_) => { - block.and(place_builder.deref()) - } - ty::UpvarCapture::ByValue(_) => block.and(place_builder), - } + block.and(PlaceBuilder::from(PlaceBase::Upvar { + var_hir_id: upvar_id.var_path.hir_id, + closure_def_id: upvar_id.closure_expr_id.to_def_id(), + closure_kind, + })) } /// Lower an index expression @@ -373,7 +607,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let is_outermost_index = fake_borrow_temps.is_none(); let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps); - let base_place = + let mut base_place = unpack!(block = self.expr_as_place(block, lhs, mutability, Some(fake_borrow_temps),)); // Making this a *fresh* temporary means we do not have to worry about @@ -383,7 +617,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = self.bounds_check( block, - base_place.clone().into_place(self.hir.tcx()), + base_place.clone().into_place(self.hir.tcx(), self.hir.typeck_results()), idx, expr_span, source_info, @@ -392,6 +626,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if is_outermost_index { self.read_fake_borrows(block, fake_borrow_temps, source_info) } else { + base_place = base_place.expect_upvars_resolved(self.hir.tcx(), self.hir.typeck_results()); self.add_fake_borrows_of_base( &base_place, block, @@ -441,8 +676,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info: SourceInfo, ) { let tcx = self.hir.tcx(); - let place_ty = - Place::ty_from(base_place.local, &base_place.projection, &self.local_decls, tcx); + let local = match base_place.base { + PlaceBase::Local(local) => local, + PlaceBase::Upvar { .. } => bug!("Expected PlacseBase::Local found Upvar") + }; + + let place_ty = Place::ty_from(local, &base_place.projection, &self.local_decls, tcx); if let ty::Slice(_) = place_ty.ty.kind() { // We need to create fake borrows to ensure that the bounds // check that we just did stays valid. Since we can't assign to @@ -452,7 +691,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match elem { ProjectionElem::Deref => { let fake_borrow_deref_ty = Place::ty_from( - base_place.local, + local, &base_place.projection[..idx], &self.local_decls, tcx, @@ -470,14 +709,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Rvalue::Ref( tcx.lifetimes.re_erased, BorrowKind::Shallow, - Place { local: base_place.local, projection }, + Place { local, projection }, ), ); fake_borrow_temps.push(fake_borrow_temp); } ProjectionElem::Index(_) => { let index_ty = Place::ty_from( - base_place.local, + local, &base_place.projection[..idx], &self.local_decls, tcx, diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 7c34b996055d3..bfb3dcb8da355 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -4,6 +4,7 @@ use rustc_index::vec::Idx; use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; +use crate::build::expr::as_place::PlaceBase; use crate::thir::*; use rustc_middle::middle::region; use rustc_middle::mir::AssertKind; @@ -11,6 +12,8 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, UpvarSubsts}; use rustc_span::Span; +use std::slice; + impl<'a, 'tcx> Builder<'a, 'tcx> { /// Returns an rvalue suitable for use until the end of the current /// scope expression. @@ -112,12 +115,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty); this.cfg.push_assign(block, source_info, Place::from(result), box_); - // initialize the box contents: + // Initialize the box contents. No scope is needed since the + // `Box` is already scheduled to be dropped. unpack!( - block = - this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value) + block = this.into( + this.hir.tcx().mk_place_deref(Place::from(result)), + None, + block, + value, + ) ); - block.and(Rvalue::Use(Operand::Move(Place::from(result)))) + let result_operand = Operand::Move(Place::from(result)); + this.record_operands_moved(slice::from_ref(&result_operand)); + block.and(Rvalue::Use(result_operand)) } ExprKind::Cast { source } => { let source = unpack!(block = this.as_operand(block, scope, source)); @@ -161,6 +171,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|f| unpack!(block = this.as_operand(block, scope, f))) .collect(); + this.record_operands_moved(&fields); block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields)) } ExprKind::Tuple { fields } => { @@ -171,6 +182,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|f| unpack!(block = this.as_operand(block, scope, f))) .collect(); + this.record_operands_moved(&fields); block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields)) } ExprKind::Closure { closure_id, substs, upvars, movability } => { @@ -222,6 +234,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs), }; + this.record_operands_moved(&operands); block.and(Rvalue::Aggregate(result, operands)) } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { @@ -381,44 +394,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) }); - let arg_place = unpack!(block = this.as_place(block, arg)); - - let mutability = match arg_place.as_ref() { - PlaceRef { local, projection: &[] } => this.local_decls[local].mutability, - PlaceRef { local, projection: &[ProjectionElem::Deref] } => { - debug_assert!( - this.local_decls[local].is_ref_for_guard(), - "Unexpected capture place", - ); - this.local_decls[local].mutability - } - PlaceRef { - local, - projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)], - } - | PlaceRef { - local, - projection: - &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref], - } => { - let place = PlaceRef { local, projection: proj_base }; - - // Not projected from the implicit `self` in a closure. - debug_assert!( - match place.local_or_deref_local() { - Some(local) => local == Local::new(1), - None => false, - }, - "Unexpected capture place" - ); - // Not in a closure - debug_assert!( - this.upvar_mutbls.len() > upvar_index.index(), - "Unexpected capture place" - ); - this.upvar_mutbls[upvar_index.index()] + let arg_place_builder = unpack!(block = this.as_place_builder(block, arg)); + + let mutability = match arg_place_builder.base() { + // We are capturing a path that starts off a local variable in the parent. + // The mutability of the current capture is same as the mutability + // of the local declaration in the parent. + PlaceBase::Local(local) => this.local_decls[local].mutability, + // Parent is a closure and we are capturing a path that is captured + // by the parent itself. The mutability of the current capture + // is same as that of the capture in the parent closure. + PlaceBase::Upvar { .. } => { + let enclosing_upvars_resolved = arg_place_builder.clone().into_place( + this.hir.tcx(), + this.hir.typeck_results()); + + match enclosing_upvars_resolved.as_ref() { + PlaceRef { local, projection: &[ProjectionElem::Field(upvar_index, _), ..] } + | PlaceRef { + local, + projection: &[ProjectionElem::Deref, ProjectionElem::Field(upvar_index, _), ..] } => { + // Not in a closure + debug_assert!( + local == Local::new(1), + "Expected local to be Local(1), found {:?}", + local + ); + // Not in a closure + debug_assert!( + this.upvar_mutbls.len() > upvar_index.index(), + "Unexpected capture place, upvar_mutbls={:#?}, upvar_index={:?}", + this.upvar_mutbls, upvar_index + ); + this.upvar_mutbls[upvar_index.index()] + } + _ => bug!("Unexpected capture place"), + } } - _ => bug!("Unexpected capture place"), }; let borrow_kind = match mutability { @@ -426,6 +438,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, }; + let arg_place = arg_place_builder.into_place( + this.hir.tcx(), + this.hir.typeck_results()); + this.cfg.push_assign( block, source_info, diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 9984b527ffdb4..241330d96e7bd 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -114,11 +114,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - unpack!(block = this.into(temp_place, block, expr)); - - if let Some(temp_lifetime) = temp_lifetime { - this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value); - } + unpack!(block = this.into(temp_place, temp_lifetime, block, expr)); block.and(temp) } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 50001c38dc737..5f9743b7f598a 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -1,28 +1,37 @@ //! See docs in build/expr/mod.rs use crate::build::expr::category::{Category, RvalueFunc}; +use crate::build::scope::DropKind; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::thir::*; use rustc_ast::InlineAsmOptions; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; +use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation}; use rustc_span::symbol::sym; - use rustc_target::spec::abi::Abi; +use std::slice; + impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. + /// If a `drop_scope` is provided, `destination` is scheduled to be dropped + /// in `scope` once it has been initialized. crate fn into_expr( &mut self, destination: Place<'tcx>, + scope: Option, mut block: BasicBlock, expr: Expr<'tcx>, ) -> BlockAnd<()> { - debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr); + debug!( + "into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})", + destination, scope, block, expr + ); // since we frequently have to reference `self` from within a // closure, where `self` would be shadowed, it's easier to @@ -37,6 +46,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => false, }; + let schedule_drop = move |this: &mut Self| { + if let Some(drop_scope) = scope { + let local = + destination.as_local().expect("cannot schedule drop of non-Local place"); + this.schedule_drop(expr_span, drop_scope, local, DropKind::Value); + } + }; + if !expr_is_block_or_scope { this.block_context.push(BlockFrame::SubExpr); } @@ -46,15 +63,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let region_scope = (region_scope, source_info); ensure_sufficient_stack(|| { this.in_scope(region_scope, lint_level, |this| { - this.into(destination, block, value) + this.into(destination, scope, block, value) }) }) } ExprKind::Block { body: ast_block } => { - this.ast_block(destination, block, ast_block, source_info) + this.ast_block(destination, scope, block, ast_block, source_info) } ExprKind::Match { scrutinee, arms } => { - this.match_expr(destination, expr_span, block, scrutinee, arms) + this.match_expr(destination, scope, expr_span, block, scrutinee, arms) } ExprKind::NeverToAny { source } => { let source = this.hir.mirror(source); @@ -66,6 +83,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // This is an optimization. If the expression was a call then we already have an // unreachable block. Don't bother to terminate it and create a new one. + schedule_drop(this); if is_call { block.unit() } else { @@ -141,26 +159,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Start the loop. this.cfg.goto(block, source_info, loop_block); - this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| { - // conduct the test, if necessary - let body_block = this.cfg.start_new_block(); - this.cfg.terminate( - loop_block, - source_info, - TerminatorKind::FalseUnwind { real_target: body_block, unwind: None }, - ); - this.diverge_from(loop_block); - - // The “return” value of the loop body must always be an unit. We therefore - // introduce a unit temporary as the destination for the loop body. - let tmp = this.get_unit_temp(); - // Execute the body, branching back to the test. - let body_block_end = unpack!(this.into(tmp, body_block, body)); - this.cfg.goto(body_block_end, source_info, loop_block); - - // Loops are only exited by `break` expressions. - None - }) + this.in_breakable_scope( + Some(loop_block), + destination, + scope, + expr_span, + move |this| { + // conduct the test, if necessary + let body_block = this.cfg.start_new_block(); + this.cfg.terminate( + loop_block, + source_info, + TerminatorKind::FalseUnwind { real_target: body_block, unwind: None }, + ); + this.diverge_from(loop_block); + + // The “return” value of the loop body must always be an unit. We therefore + // introduce a unit temporary as the destination for the loop body. + let tmp = this.get_unit_temp(); + // Execute the body, branching back to the test. + // We don't need to provide a drop scope because `tmp` + // has type `()`. + let body_block_end = unpack!(this.into(tmp, None, body_block, body)); + this.cfg.goto(body_block_end, source_info, loop_block); + schedule_drop(this); + + // Loops are only exited by `break` expressions. + None + }, + ) } ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => { let intrinsic = match *ty.kind() { @@ -192,8 +219,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .local_decls .push(LocalDecl::with_source_info(ptr_ty, source_info).internal()); let ptr_temp = Place::from(ptr_temp); - let block = unpack!(this.into(ptr_temp, block, ptr)); - this.into(this.hir.tcx().mk_place_deref(ptr_temp), block, val) + // No need for a scope, ptr_temp doesn't need drop + let block = unpack!(this.into(ptr_temp, None, block, ptr)); + // Maybe we should provide a scope here so that + // `move_val_init` wouldn't leak on panic even with an + // arbitrary `val` expression, but `schedule_drop`, + // borrowck and drop elaboration all prevent us from + // dropping `ptr_temp.deref()`. + this.into(this.hir.tcx().mk_place_deref(ptr_temp), None, block, val) } else { let args: Vec<_> = args .into_iter() @@ -226,10 +259,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ); this.diverge_from(block); + schedule_drop(this); success.unit() } } - ExprKind::Use { source } => this.into(destination, block, source), + ExprKind::Use { source } => this.into(destination, scope, block, source), ExprKind::Borrow { arg, borrow_kind } => { // We don't do this in `as_rvalue` because we use `as_place` // for borrow expressions, so we cannot create an `RValue` that @@ -271,7 +305,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let field_names = this.hir.all_fields(adt_def, variant_index); - let fields = if let Some(FruInfo { base, field_types }) = base { + let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base { let base = unpack!(block = this.as_place(block, base)); // MIR does not natively support FRU, so for each @@ -306,12 +340,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { user_ty, active_field_index, ); + this.record_operands_moved(&fields); this.cfg.push_assign( block, source_info, destination, Rvalue::Aggregate(adt, fields), ); + schedule_drop(this); block.unit() } ExprKind::InlineAsm { template, operands, options, line_spans } => { @@ -408,6 +444,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = unpack!(block = this.as_place(block, expr)); let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); this.cfg.push_assign(block, source_info, destination, rvalue); + schedule_drop(this); block.unit() } ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => { @@ -425,6 +462,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = unpack!(block = this.as_place(block, expr)); let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); this.cfg.push_assign(block, source_info, destination, rvalue); + schedule_drop(this); block.unit() } @@ -432,12 +470,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scope = this.local_scope(); let value = unpack!(block = this.as_operand(block, scope, value)); let resume = this.cfg.start_new_block(); + this.record_operands_moved(slice::from_ref(&value)); this.cfg.terminate( block, source_info, TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None }, ); this.generator_drop_cleanup(block); + schedule_drop(this); resume.unit() } @@ -469,6 +509,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rvalue = unpack!(block = this.as_local_rvalue(block, expr)); this.cfg.push_assign(block, source_info, destination, rvalue); + schedule_drop(this); block.unit() } }; diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index f117689d940fd..a974ea0db5f3c 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -3,6 +3,7 @@ use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::thir::*; use rustc_middle::middle::region; use rustc_middle::mir::*; +use std::slice; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Builds a block of MIR statements to evaluate the THIR `expr`. @@ -46,6 +47,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if this.hir.needs_drop(lhs.ty) { let rhs = unpack!(block = this.as_local_operand(block, rhs)); let lhs = unpack!(block = this.as_place(block, lhs)); + this.record_operands_moved(slice::from_ref(&rhs)); unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs)); } else { let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); diff --git a/compiler/rustc_mir_build/src/build/into.rs b/compiler/rustc_mir_build/src/build/into.rs index 7264e495b84fd..ee1838ddea66c 100644 --- a/compiler/rustc_mir_build/src/build/into.rs +++ b/compiler/rustc_mir_build/src/build/into.rs @@ -6,6 +6,7 @@ use crate::build::{BlockAnd, Builder}; use crate::thir::*; +use rustc_middle::middle::region; use rustc_middle::mir::*; pub(in crate::build) trait EvalInto<'tcx> { @@ -13,6 +14,7 @@ pub(in crate::build) trait EvalInto<'tcx> { self, builder: &mut Builder<'_, 'tcx>, destination: Place<'tcx>, + scope: Option, block: BasicBlock, ) -> BlockAnd<()>; } @@ -21,13 +23,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn into( &mut self, destination: Place<'tcx>, + scope: Option, block: BasicBlock, expr: E, ) -> BlockAnd<()> where E: EvalInto<'tcx>, { - expr.eval_into(self, destination, block) + expr.eval_into(self, destination, scope, block) } } @@ -36,10 +39,11 @@ impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> { self, builder: &mut Builder<'_, 'tcx>, destination: Place<'tcx>, + scope: Option, block: BasicBlock, ) -> BlockAnd<()> { let expr = builder.hir.mirror(self); - builder.into_expr(destination, block, expr) + builder.into_expr(destination, scope, block, expr) } } @@ -48,8 +52,9 @@ impl<'tcx> EvalInto<'tcx> for Expr<'tcx> { self, builder: &mut Builder<'_, 'tcx>, destination: Place<'tcx>, + scope: Option, block: BasicBlock, ) -> BlockAnd<()> { - builder.into_expr(destination, block, self) + builder.into_expr(destination, scope, block, self) } } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 3ee15248ae28e..7ffdb7e33fb1e 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -87,6 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn match_expr( &mut self, destination: Place<'tcx>, + destination_scope: Option, span: Span, mut block: BasicBlock, scrutinee: ExprRef<'tcx>, @@ -107,6 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.lower_match_arms( destination, + destination_scope, scrutinee_place, scrutinee_span, arm_candidates, @@ -213,75 +215,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - /// Lower the bindings, guards and arm bodies of a `match` expression. - /// - /// The decision tree should have already been created - /// (by [Builder::lower_match_tree]). - /// - /// `outer_source_info` is the SourceInfo for the whole match. - fn lower_match_arms( - &mut self, - destination: Place<'tcx>, - scrutinee_place: Place<'tcx>, - scrutinee_span: Span, - arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, - outer_source_info: SourceInfo, - fake_borrow_temps: Vec<(Place<'tcx>, Local)>, - ) -> BlockAnd<()> { - let arm_end_blocks: Vec<_> = arm_candidates - .into_iter() - .map(|(arm, candidate)| { - debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate); - - let arm_source_info = self.source_info(arm.span); - let arm_scope = (arm.scope, arm_source_info); - self.in_scope(arm_scope, arm.lint_level, |this| { - let body = this.hir.mirror(arm.body.clone()); - let scope = this.declare_bindings( - None, - arm.span, - &arm.pattern, - ArmHasGuard(arm.guard.is_some()), - Some((Some(&scrutinee_place), scrutinee_span)), - ); - - let arm_block = this.bind_pattern( - outer_source_info, - candidate, - arm.guard.as_ref(), - &fake_borrow_temps, - scrutinee_span, - Some(arm.scope), - ); - - if let Some(source_scope) = scope { - this.source_scope = source_scope; - } - - this.into(destination, arm_block, body) - }) - }) - .collect(); - - // all the arm blocks will rejoin here - let end_block = self.cfg.start_new_block(); - - for arm_block in arm_end_blocks { - self.cfg.goto(unpack!(arm_block), outer_source_info, end_block); - } - - self.source_scope = outer_source_info.scope; - - end_block.unit() - } - /// Binds the variables and ascribes types for a given `match` arm or /// `let` binding. /// /// Also check if the guard matches, if it's provided. /// `arm_scope` should be `Some` if and only if this is called for a /// `match` arm. - fn bind_pattern( + crate fn bind_pattern( &mut self, outer_source_info: SourceInfo, candidate: Candidate<'_, 'tcx>, @@ -365,13 +305,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => { let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); - unpack!(block = self.into(place, block, initializer)); + let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); + + unpack!(block = self.into(place, Some(region_scope), block, initializer)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let source_info = self.source_info(irrefutable_pat.span); self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet, place); - self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() } @@ -398,9 +339,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascription: thir::pattern::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span }, } => { + let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); - unpack!(block = self.into(place, block, initializer)); + unpack!(block = self.into(place, Some(region_scope), block, initializer)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let pattern_source_info = self.source_info(irrefutable_pat.span); @@ -438,7 +380,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ); - self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() } @@ -684,7 +625,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } #[derive(Debug)] -struct Candidate<'pat, 'tcx> { +pub(super) struct Candidate<'pat, 'tcx> { /// `Span` of the original pattern that gave rise to this candidate span: Span, @@ -1394,12 +1335,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match test.kind { TestKind::SwitchInt { switch_ty, ref mut options } => { for candidate in candidates.iter() { - if !self.add_cases_to_switch( - &match_place, - candidate, - switch_ty, - options, - ) { + if !self.add_cases_to_switch(&match_place, candidate, switch_ty, options) { break; } } @@ -1780,14 +1716,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` // // and that is clearly not correct. - let by_value_bindings = - parent_bindings - .iter() - .flat_map(|(bindings, _)| bindings) - .chain(&candidate.bindings) - .filter(|binding| { - matches!(binding.binding_mode, BindingMode::ByValue ) - }); + let by_value_bindings = parent_bindings + .iter() + .flat_map(|(bindings, _)| bindings) + .chain(&candidate.bindings) + .filter(|binding| matches!(binding.binding_mode, BindingMode::ByValue)); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. for binding in by_value_bindings.clone() { diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index c50389a850ec6..d7fce15d99669 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{GeneratorKind, HirIdMap, Node}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::ty::subst::Subst; @@ -75,7 +76,9 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ kind: hir::TraitItemKind::Const(ty, Some(body_id)), .. }) => (*body_id, ty.span, None), - Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => (*body, tcx.hir().span(*hir_id), None), + Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => { + (*body, tcx.hir().span(*hir_id), None) + } _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def.did), }; @@ -183,7 +186,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ return_ty, return_ty_span, body, - span_with_body + span_with_body, ); mir.yield_ty = yield_ty; mir @@ -581,7 +584,7 @@ fn construct_fn<'a, 'tcx, A>( return_ty: Ty<'tcx>, return_ty_span: Span, body: &'tcx hir::Body<'tcx>, - span_with_body: Span + span_with_body: Span, ) -> Body<'tcx> where A: Iterator>, @@ -615,8 +618,12 @@ where let arg_scope_s = (arg_scope, source_info); // Attribute epilogue to function's closing brace let fn_end = span_with_body.shrink_to_hi(); - let return_block = - unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { + let return_block = unpack!(builder.in_breakable_scope( + None, + Place::return_place(), + Some(call_site_scope), + fn_end, + |builder| { Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { builder.args_and_body( START_BLOCK, @@ -626,11 +633,13 @@ where &body.value, ) })) - })); + }, + )); let source_info = builder.source_info(fn_end); builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); let should_abort = should_abort_on_panic(tcx, fn_def_id, abi); builder.build_drop_trees(should_abort); + builder.unschedule_return_place_drop(); return_block.unit() })); @@ -657,12 +666,15 @@ fn construct_const<'a, 'tcx>( let owner_id = tcx.hir().body_owner(body_id); let def_id = tcx.hir().local_def_id(owner_id); let span = tcx.hir().span(owner_id); - let mut builder = Builder::new(hir, def_id.to_def_id(), span, 0, Safety::Safe, const_ty, const_ty_span, None); + let mut builder = + Builder::new(hir, def_id.to_def_id(), span, 0, Safety::Safe, const_ty, const_ty_span, None); let mut block = START_BLOCK; let ast_expr = &tcx.hir().body(body_id).value; let expr = builder.hir.mirror(ast_expr); - unpack!(block = builder.into_expr(Place::return_place(), block, expr)); + // We don't provide a scope because we can't unwind in constants, so won't + // need to drop the return place. + unpack!(block = builder.into_expr(Place::return_place(), None, block, expr)); let source_info = builder.source_info(span); builder.cfg.terminate(block, source_info, TerminatorKind::Return); @@ -697,7 +709,8 @@ fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'t hir::BodyOwnerKind::Const => 0, hir::BodyOwnerKind::Static(_) => 0, }; - let mut builder = Builder::new(hir, def_id.to_def_id(), span, num_params, Safety::Safe, ty, span, None); + let mut builder = + Builder::new(hir, def_id.to_def_id(), span, num_params, Safety::Safe, ty, span, None); let source_info = builder.source_info(span); // Some MIR passes will expect the number of parameters to match the // function declaration. @@ -811,7 +824,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // with the closure's DefId. Here, we run through that vec of UpvarIds for // the given closure and use the necessary information to create upvar // debuginfo and to fill `self.upvar_mutbls`. - if let Some(upvars) = hir_typeck_results.closure_captures.get(&fn_def_id) { + if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() { let closure_env_arg = Local::new(1); let mut closure_env_projs = vec![]; let mut closure_ty = self.local_decls[closure_env_arg].ty; @@ -824,14 +837,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty), }; - let upvar_tys = upvar_substs.upvar_tys(); - let upvars_with_tys = upvars.iter().zip(upvar_tys); - self.upvar_mutbls = upvars_with_tys + let capture_tys = upvar_substs.upvar_tys(); + let captures_with_tys = hir_typeck_results + .closure_min_captures_flattened(fn_def_id) + .zip(capture_tys); + + self.upvar_mutbls = captures_with_tys .enumerate() - .map(|(i, ((&var_id, &upvar_id), ty))| { - let capture = hir_typeck_results.upvar_capture(upvar_id); + .map(|(i, (captured_place, ty))| { + let capture = captured_place.info.capture_kind; + let var_id = match captured_place.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + _ => bug!("Expected an upvar") + }; let mut mutability = Mutability::Not; + + // FIXME(project-rfc-2229#8): Store more precise information let mut name = kw::Invalid; if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) { if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { @@ -941,7 +963,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let body = self.hir.mirror(ast_body); - self.into(Place::return_place(), block, body) + let call_site = + region::Scope { id: ast_body.hir_id.local_id, data: region::ScopeData::CallSite }; + self.into(Place::return_place(), Some(call_site), block, body) } fn set_correct_source_scope_for_arg( diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index e91227d8357de..468b3484ca5ea 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -81,9 +81,10 @@ that contains only loops and breakable blocks. It tracks where a `break`, */ +use crate::build::matches::{ArmHasGuard, Candidate}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; -use crate::thir::{Expr, ExprRef, LintLevel}; -use rustc_data_structures::fx::FxHashMap; +use crate::thir::{Arm, Expr, ExprRef, LintLevel}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_index::vec::IndexVec; use rustc_middle::middle::region; @@ -121,8 +122,6 @@ struct Scope { /// end of the vector (top of the stack) first. drops: Vec, - moved_locals: Vec, - /// The drop index that will drop everything in and below this scope on an /// unwind path. cached_unwind_block: Option, @@ -158,6 +157,8 @@ struct BreakableScope<'tcx> { /// The destination of the loop/block expression itself (i.e., where to put /// the result of a `break` or `return` expression) break_destination: Place<'tcx>, + /// The scope that the destination should have its drop scheduled in. + destination_scope: Option, /// Drops that happen on the `break`/`return` path. break_drops: DropTree, /// Drops that happen on the `continue` path. @@ -406,7 +407,6 @@ impl<'tcx> Scopes<'tcx> { region_scope: region_scope.0, region_scope_span: region_scope.1.span, drops: vec![], - moved_locals: vec![], cached_unwind_block: None, cached_generator_drop_block: None, }); @@ -441,6 +441,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, loop_block: Option, break_destination: Place<'tcx>, + destination_scope: Option, span: Span, f: F, ) -> BlockAnd<()> @@ -451,15 +452,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scope = BreakableScope { region_scope, break_destination, + destination_scope, break_drops: DropTree::new(), continue_drops: loop_block.map(|_| DropTree::new()), }; + let continue_block = loop_block.map(|block| (block, self.diverge_cleanup())); self.scopes.breakable_scopes.push(scope); let normal_exit_block = f(self); let breakable_scope = self.scopes.breakable_scopes.pop().unwrap(); assert!(breakable_scope.region_scope == region_scope); + if let Some(drops) = breakable_scope.continue_drops { + self.build_exit_tree(drops, continue_block); + } let break_block = self.build_exit_tree(breakable_scope.break_drops, None); - if let Some(drops) = breakable_scope.continue_drops { self.build_exit_tree(drops, loop_block); } match (normal_exit_block, break_block) { (Some(block), None) | (None, Some(block)) => block, (None, None) => self.cfg.start_new_block().unit(), @@ -588,22 +593,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .rposition(|breakable_scope| breakable_scope.region_scope == scope) .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found")) }; - let (break_index, destination) = match target { + let (break_index, destination, dest_scope) = match target { BreakableTarget::Return => { let scope = &self.scopes.breakable_scopes[0]; if scope.break_destination != Place::return_place() { span_bug!(span, "`return` in item with no return scope"); } - (0, Some(scope.break_destination)) + (0, Some(scope.break_destination), scope.destination_scope) } BreakableTarget::Break(scope) => { let break_index = get_scope_index(scope); let scope = &self.scopes.breakable_scopes[break_index]; - (break_index, Some(scope.break_destination)) + (break_index, Some(scope.break_destination), scope.destination_scope) } BreakableTarget::Continue(scope) => { let break_index = get_scope_index(scope); - (break_index, None) + (break_index, None, None) } }; @@ -611,7 +616,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(value) = value { debug!("stmt_expr Break val block_context.push(SubExpr)"); self.block_context.push(BlockFrame::SubExpr); - unpack!(block = self.into(destination, block, value)); + unpack!(block = self.into(destination, dest_scope, block, value)); + dest_scope + .map(|scope| self.unschedule_drop(scope, destination.as_local().unwrap())); self.block_context.pop(); } else { self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx()) @@ -861,14 +868,47 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local); } - /// Indicates that the "local operand" stored in `local` is + /// Unschedule a drop. Used for `break`, `return` and `match` expressions, + /// where `record_operands_moved` is not powerful enough. + /// + /// The given local is expected to have a value drop scheduled in the given + /// scope and for that drop to be the most recent thing scheduled in that + /// scope. + fn unschedule_drop(&mut self, region_scope: region::Scope, local: Local) { + if !self.hir.needs_drop(self.local_decls[local].ty) { + return; + } + for scope in self.scopes.scopes.iter_mut().rev() { + scope.invalidate_cache(); + + if scope.region_scope == region_scope { + let drop = scope.drops.pop(); + + match drop { + Some(DropData { local: removed_local, kind: DropKind::Value, .. }) + if removed_local == local => + { + return; + } + _ => bug!( + "found wrong drop, expected value drop of {:?}, found {:?}", + local, + drop, + ), + } + } + } + + bug!("region scope {:?} not in scope to unschedule drop of {:?}", region_scope, local); + } + + /// Indicates that the "local operands" stored in `local` is /// *moved* at some point during execution (see `local_scope` for /// more information about what a "local operand" is -- in short, /// it's an intermediate operand created as part of preparing some /// MIR instruction). We use this information to suppress - /// redundant drops on the non-unwind paths. This results in less - /// MIR, but also avoids spurious borrow check errors - /// (c.f. #64391). + /// redundant drops. This results in less MIR, but also avoids spurious + /// borrow check errors (c.f. #64391). /// /// Example: when compiling the call to `foo` here: /// @@ -904,29 +944,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return; } - Some(local_scope) => self - .scopes - .scopes - .iter_mut() - .rfind(|scope| scope.region_scope == local_scope) - .unwrap_or_else(|| bug!("scope {:?} not found in scope list!", local_scope)), + Some(local_scope) => { + let top_scope = self.scopes.scopes.last_mut().unwrap(); + assert!( + top_scope.region_scope == local_scope, + "local scope ({:?}) is not the topmost scope!", + local_scope + ); + + top_scope + } }; // look for moves of a local variable, like `MOVE(_X)` - let locals_moved = operands.iter().flat_map(|operand| match operand { - Operand::Copy(_) | Operand::Constant(_) => None, - Operand::Move(place) => place.as_local(), - }); + let locals_moved = operands + .iter() + .filter_map(|operand| match operand { + Operand::Copy(_) | Operand::Constant(_) => None, + Operand::Move(place) => place.as_local(), + }) + .collect::>(); - for local in locals_moved { - // check if we have a Drop for this operand and -- if so - // -- add it to the list of moved operands. Note that this - // local might not have been an operand created for this - // call, it could come from other places too. - if scope.drops.iter().any(|drop| drop.local == local && drop.kind == DropKind::Value) { - scope.moved_locals.push(local); - } - } + // Remove the drops for the moved operands. + scope + .drops + .retain(|drop| drop.kind == DropKind::Storage || !locals_moved.contains(&drop.local)); + scope.invalidate_cache(); } // Other @@ -1116,11 +1159,96 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { success_block } + /// Lower the arms and guards of a match. + /// + /// The decision tree should have already been created (by + /// [Builder::lower_match_tree]). + /// + /// This is this module, and not in `build::matches` because we have to do + /// some careful scope manipulation to have the drop of the destination be + /// scheduled at the end of each arm and then cleared for the next arm. + crate fn lower_match_arms( + &mut self, + destination: Place<'tcx>, + destination_scope: Option, + scrutinee_place: Place<'tcx>, + scrutinee_span: Span, + arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, + outer_source_info: SourceInfo, + fake_borrow_temps: Vec<(Place<'tcx>, Local)>, + ) -> BlockAnd<()> { + if arm_candidates.is_empty() { + // If there are no arms to schedule drops, then we have to do it + // manually. + if let Some(scope) = destination_scope { + self.schedule_drop( + outer_source_info.span, + scope, + destination.as_local().unwrap(), + DropKind::Value, + ); + } + return self.cfg.start_new_block().unit(); + } + let mut first_arm = true; + let arm_end_blocks: Vec<_> = arm_candidates + .into_iter() + .map(|(arm, candidate)| { + debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate); + + if first_arm { + first_arm = false; + } else if let Some(scope) = destination_scope { + self.unschedule_drop(scope, destination.as_local().unwrap()); + } + + let arm_source_info = self.source_info(arm.span); + let arm_scope = (arm.scope, arm_source_info); + self.in_scope(arm_scope, arm.lint_level, |this| { + let body = this.hir.mirror(arm.body.clone()); + let scope = this.declare_bindings( + None, + arm.span, + &arm.pattern, + ArmHasGuard(arm.guard.is_some()), + Some((Some(&scrutinee_place), scrutinee_span)), + ); + + let arm_block = this.bind_pattern( + outer_source_info, + candidate, + arm.guard.as_ref(), + &fake_borrow_temps, + scrutinee_span, + Some(arm.scope), + ); + + if let Some(source_scope) = scope { + this.source_scope = source_scope; + } + + this.into(destination, destination_scope, arm_block, body) + }) + }) + .collect(); + + // all the arm blocks will rejoin here + let end_block = self.cfg.start_new_block(); + + for arm_block in arm_end_blocks { + self.cfg.goto(unpack!(arm_block), outer_source_info, end_block); + } + + self.source_scope = outer_source_info.scope; + + end_block.unit() + } + /// Unschedules any drops in the top scope. /// /// This is only needed for `match` arm scopes, because they have one /// entrance per pattern, but only one exit. - crate fn clear_top_scope(&mut self, region_scope: region::Scope) { + pub(super) fn clear_top_scope(&mut self, region_scope: region::Scope) { let top_scope = self.scopes.scopes.last_mut().unwrap(); assert_eq!(top_scope.region_scope, region_scope); @@ -1128,6 +1256,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { top_scope.drops.clear(); top_scope.invalidate_cache(); } + + /// Unschedules the drop of the return place. + /// + /// If the return type of a function requires drop, then we schedule it + /// in the outermost scope so that it's dropped if there's a panic while + /// we drop any local variables. But we don't want to drop it if we + /// return normally. + crate fn unschedule_return_place_drop(&mut self) { + assert_eq!(self.scopes.scopes.len(), 1); + assert!(self.scopes.scopes[0].drops.len() <= 1); + self.scopes.scopes[0].drops.clear(); + } } /// Builds drops for `pop_scope` and `leave_top_scope`. @@ -1174,14 +1314,6 @@ fn build_scope_drops<'tcx>( debug_assert_eq!(unwind_drops.drops[unwind_to].0.kind, drop_data.kind); unwind_to = unwind_drops.drops[unwind_to].1; - // If the operand has been moved, and we are not on an unwind - // path, then don't generate the drop. (We only take this into - // account for non-unwind paths so as not to disturb the - // caching mechanism.) - if scope.moved_locals.iter().any(|&o| o == local) { - continue; - } - unwind_drops.add_entry(block, unwind_to); let next = cfg.start_new_block(); @@ -1211,20 +1343,24 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { /// Build a drop tree for a breakable scope. /// /// If `continue_block` is `Some`, then the tree is for `continue` inside a - /// loop. Otherwise this is for `break` or `return`. + /// loop. Otherwise this is for `break` or `return`. The `DropIdx` is the + /// next drop in the case that the drop tree unwinds. This is needed + /// because the drop of the break destination has already been scheduled + /// but it hasn't been initialized on the `continue` paths. fn build_exit_tree( &mut self, mut drops: DropTree, - continue_block: Option, + continue_block: Option<(BasicBlock, DropIdx)>, ) -> Option> { let mut blocks = IndexVec::from_elem(None, &drops.drops); - blocks[ROOT_NODE] = continue_block; + blocks[ROOT_NODE] = continue_block.map(|(block, _)| block); drops.build_mir::(&mut self.cfg, &mut blocks); // Link the exit drop tree to unwind drop tree. if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) { - let unwind_target = self.diverge_cleanup(); + let unwind_target = continue_block + .map_or_else(|| self.diverge_cleanup(), |(_, unwind_target)| unwind_target); let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1); for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) { match drop_data.0.kind { @@ -1387,7 +1523,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind { | TerminatorKind::Yield { .. } | TerminatorKind::GeneratorDrop | TerminatorKind::FalseEdge { .. } - | TerminatorKind::InlineAsm {.. } => { + | TerminatorKind::InlineAsm { .. } => { span_bug!(term.source_info.span, "cannot unwind from {:?}", term.kind) } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index e404afeb698a6..d6695a5500d1b 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -6,6 +6,8 @@ use crate::thir::*; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_index::vec::Idx; +use rustc_middle::hir::place::PlaceBase as HirPlaceBase; +use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::BorrowKind; use rustc_middle::ty::adjustment::{ @@ -386,14 +388,12 @@ fn make_mirror_unadjusted<'a, 'tcx>( span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); } }; + let upvars = cx .typeck_results() - .closure_captures - .get(&def_id) - .iter() - .flat_map(|upvars| upvars.iter()) + .closure_min_captures_flattened(def_id) .zip(substs.upvar_tys()) - .map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty)) + .map(|(captured_place, ty)| capture_upvar(cx, expr, captured_place, ty)) .collect(); ExprKind::Closure { closure_id: def_id, substs, upvars, movability } } @@ -981,27 +981,55 @@ fn overloaded_place<'a, 'tcx>( ExprKind::Deref { arg: ref_expr.to_ref() } } -fn capture_upvar<'tcx>( +fn capture_upvar<'a, 'tcx>( cx: &mut Cx<'_, 'tcx>, closure_expr: &'tcx hir::Expr<'tcx>, - var_hir_id: hir::HirId, + captured_place: &'a ty::CapturedPlace<'tcx>, upvar_ty: Ty<'tcx>, ) -> ExprRef<'tcx> { - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: cx.tcx.hir().local_def_id(closure_expr.hir_id), - }; - let upvar_capture = cx.typeck_results().upvar_capture(upvar_id); + let upvar_capture = captured_place.info.capture_kind; let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); - let var_ty = cx.typeck_results().node_type(var_hir_id); - let captured_var = Expr { + let var_ty = captured_place.place.base_ty; + + // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path + // as it's seen for use within the closure and not at the time of closure creation. + // + // That is we see expect to see it start from a captured upvar and not something that is local + // to the closure's parent. + let var_hir_id = match captured_place.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, + base => bug!("Expected an upvar, found {:?}", base), + }; + + let mut captured_place_expr = Expr { temp_lifetime, ty: var_ty, span: closure_expr.span, kind: convert_var(cx, var_hir_id), }; + + for proj in captured_place.place.projections.iter() { + let kind = match proj.kind { + HirProjectionKind::Deref => ExprKind::Deref { arg: captured_place_expr.to_ref() }, + HirProjectionKind::Field(field, ..) => { + // Variant index will always be 0, because for multi-variant + // enums, we capture the enum entirely. + ExprKind::Field { + lhs: captured_place_expr.to_ref(), + name: Field::new(field as usize), + } + } + HirProjectionKind::Index | HirProjectionKind::Subslice => { + // We don't capture these projections, so we can ignore them here + continue; + } + }; + + captured_place_expr = Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind }; + } + match upvar_capture { - ty::UpvarCapture::ByValue(_) => captured_var.to_ref(), + ty::UpvarCapture::ByValue(_) => captured_place_expr.to_ref(), ty::UpvarCapture::ByRef(upvar_borrow) => { let borrow_kind = match upvar_borrow.kind { ty::BorrowKind::ImmBorrow => BorrowKind::Shared, @@ -1012,7 +1040,7 @@ fn capture_upvar<'tcx>( temp_lifetime, ty: upvar_ty, span: closure_expr.span, - kind: ExprKind::Borrow { borrow_kind, arg: captured_var.to_ref() }, + kind: ExprKind::Borrow { borrow_kind, arg: captured_place_expr.to_ref() }, } .to_ref() } diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 3b2eef5a905dd..8b21a9b24e6e2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -697,6 +697,8 @@ impl<'tcx> Constructor<'tcx> { /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`. /// For the simple cases, this is simply checking for equality. For the "grouped" constructors, /// this checks for inclusion. + // We inline because this has a single call site in `Matrix::specialize_constructor`. + #[inline] pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool { // This must be kept in sync with `is_covered_by_any`. match (self, other) { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index ee9a6dca5ade9..b62c737380087 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -18,7 +18,7 @@ pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here"; /// Whether or not an or-pattern should be gated when occurring in the current context. -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] pub(super) enum GateOr { Yes, No, @@ -94,7 +94,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P> { // Parse the first pattern (`p_0`). let first_pat = self.parse_pat(expected)?; - self.maybe_recover_unexpected_comma(first_pat.span, rc)?; + self.maybe_recover_unexpected_comma(first_pat.span, rc, gate_or)?; // If the next token is not a `|`, // this is not an or-pattern and we should exit here. @@ -110,7 +110,7 @@ impl<'a> Parser<'a> { err.span_label(lo, WHILE_PARSING_OR_MSG); err })?; - self.maybe_recover_unexpected_comma(pat.span, rc)?; + self.maybe_recover_unexpected_comma(pat.span, rc, gate_or)?; pats.push(pat); } let or_pattern_span = lo.to(self.prev_token.span); @@ -190,7 +190,12 @@ impl<'a> Parser<'a> { /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - fn maybe_recover_unexpected_comma(&mut self, lo: Span, rc: RecoverComma) -> PResult<'a, ()> { + fn maybe_recover_unexpected_comma( + &mut self, + lo: Span, + rc: RecoverComma, + gate_or: GateOr, + ) -> PResult<'a, ()> { if rc == RecoverComma::No || self.token != token::Comma { return Ok(()); } @@ -209,18 +214,24 @@ impl<'a> Parser<'a> { let seq_span = lo.to(self.prev_token.span); let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { + const MSG: &str = "try adding parentheses to match on a tuple..."; + + let or_suggestion = + gate_or == GateOr::No || !self.sess.gated_spans.is_ungated(sym::or_patterns); err.span_suggestion( seq_span, - "try adding parentheses to match on a tuple...", + if or_suggestion { MSG } else { MSG.trim_end_matches('.') }, format!("({})", seq_snippet), Applicability::MachineApplicable, - ) - .span_suggestion( - seq_span, - "...or a vertical bar to match on multiple alternatives", - seq_snippet.replace(",", " |"), - Applicability::MachineApplicable, ); + if or_suggestion { + err.span_suggestion( + seq_span, + "...or a vertical bar to match on multiple alternatives", + seq_snippet.replace(",", " |"), + Applicability::MachineApplicable, + ); + } } Err(err) } diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index df6667a29d50b..c87799f1c2acc 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -18,3 +18,4 @@ rustc_ast = { path = "../rustc_ast" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_lexer = { path = "../rustc_lexer" } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c9e02d56f4b28..fc97ca035b9b4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -78,7 +78,7 @@ impl CheckAttrVisitor<'tcx> { } else if self.tcx.sess.check_name(attr, sym::track_caller) { self.check_track_caller(&attr.span, attrs, span, target) } else if self.tcx.sess.check_name(attr, sym::doc) { - self.check_doc_alias(attr, hir_id, target) + self.check_doc_attrs(attr, hir_id, target) } else if self.tcx.sess.check_name(attr, sym::no_link) { self.check_no_link(&attr, span, target) } else if self.tcx.sess.check_name(attr, sym::export_name) { @@ -287,99 +287,159 @@ impl CheckAttrVisitor<'tcx> { } } - fn doc_alias_str_error(&self, meta: &NestedMetaItem) { + fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) { self.tcx .sess .struct_span_err( meta.span(), - "doc alias attribute expects a string: #[doc(alias = \"0\")]", + &format!("doc {0} attribute expects a string: #[doc({0} = \"a\")]", attr_name), ) .emit(); } - fn check_doc_alias(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool { + fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool { + let doc_alias = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); + if doc_alias.is_empty() { + self.doc_attr_str_error(meta, "alias"); + return false; + } + if let Some(c) = + doc_alias.chars().find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) + { + self.tcx + .sess + .struct_span_err( + meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + &format!("{:?} character isn't allowed in `#[doc(alias = \"...\")]`", c,), + ) + .emit(); + return false; + } + if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') { + self.tcx + .sess + .struct_span_err( + meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + "`#[doc(alias = \"...\")]` cannot start or end with ' '", + ) + .emit(); + return false; + } + if let Some(err) = match target { + Target::Impl => Some("implementation block"), + Target::ForeignMod => Some("extern block"), + Target::AssocTy => { + let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); + let containing_item = self.tcx.hir().expect_item(parent_hir_id); + if Target::from_item(containing_item) == Target::Impl { + Some("type alias in implementation block") + } else { + None + } + } + Target::AssocConst => { + let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); + let containing_item = self.tcx.hir().expect_item(parent_hir_id); + // We can't link to trait impl's consts. + let err = "associated constant in trait implementation block"; + match containing_item.kind { + ItemKind::Impl { of_trait: Some(_), .. } => Some(err), + _ => None, + } + } + _ => None, + } { + self.tcx + .sess + .struct_span_err( + meta.span(), + &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err), + ) + .emit(); + return false; + } + true + } + + fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool { + let doc_keyword = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); + if doc_keyword.is_empty() { + self.doc_attr_str_error(meta, "keyword"); + return false; + } + match self.tcx.hir().expect_item(hir_id).kind { + ItemKind::Mod(ref module) => { + if !module.item_ids.is_empty() { + self.tcx + .sess + .struct_span_err( + meta.span(), + "`#[doc(keyword = \"...\")]` can only be used on empty modules", + ) + .emit(); + return false; + } + } + _ => { + self.tcx + .sess + .struct_span_err( + meta.span(), + "`#[doc(keyword = \"...\")]` can only be used on modules", + ) + .emit(); + return false; + } + } + if !rustc_lexer::is_ident(&doc_keyword) { + self.tcx + .sess + .struct_span_err( + meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + &format!("`{}` is not a valid identifier", doc_keyword), + ) + .emit(); + return false; + } + true + } + + fn check_attr_crate_level( + &self, + meta: &NestedMetaItem, + hir_id: HirId, + attr_name: &str, + ) -> bool { + if CRATE_HIR_ID == hir_id { + self.tcx + .sess + .struct_span_err( + meta.span(), + &format!( + "`#![doc({} = \"...\")]` isn't allowed as a crate level attribute", + attr_name, + ), + ) + .emit(); + return false; + } + true + } + + fn check_doc_attrs(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool { if let Some(mi) = attr.meta() { if let Some(list) = mi.meta_item_list() { for meta in list { if meta.has_name(sym::alias) { - if !meta.is_value_str() { - self.doc_alias_str_error(meta); - return false; - } - let doc_alias = - meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); - if doc_alias.is_empty() { - self.doc_alias_str_error(meta); - return false; - } - if let Some(c) = doc_alias - .chars() - .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) + if !self.check_attr_crate_level(meta, hir_id, "alias") + || !self.check_doc_alias(meta, hir_id, target) { - self.tcx - .sess - .struct_span_err( - meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - &format!( - "{:?} character isn't allowed in `#[doc(alias = \"...\")]`", - c, - ), - ) - .emit(); return false; } - if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') { - self.tcx - .sess - .struct_span_err( - meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - "`#[doc(alias = \"...\")]` cannot start or end with ' '", - ) - .emit(); - return false; - } - if let Some(err) = match target { - Target::Impl => Some("implementation block"), - Target::ForeignMod => Some("extern block"), - Target::AssocTy => { - let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); - let containing_item = self.tcx.hir().expect_item(parent_hir_id); - if Target::from_item(containing_item) == Target::Impl { - Some("type alias in implementation block") - } else { - None - } - } - Target::AssocConst => { - let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); - let containing_item = self.tcx.hir().expect_item(parent_hir_id); - // We can't link to trait impl's consts. - let err = "associated constant in trait implementation block"; - match containing_item.kind { - ItemKind::Impl { of_trait: Some(_), .. } => Some(err), - _ => None, - } - } - _ => None, - } { - self.tcx - .sess - .struct_span_err( - meta.span(), - &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err), - ) - .emit(); - return false; - } - if CRATE_HIR_ID == hir_id { - self.tcx - .sess - .struct_span_err( - meta.span(), - "`#![doc(alias = \"...\")]` isn't allowed as a crate \ - level attribute", - ) - .emit(); + } else if meta.has_name(sym::keyword) { + if !self.check_attr_crate_level(meta, hir_id, "keyword") + || !self.check_doc_keyword(meta, hir_id) + { return false; } } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 91edbebc05f3b..69f28045bb5bd 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1098,7 +1098,7 @@ fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shado ) }; err.span_label(orig.span, "first declared here"); - err.span_label(shadower.span, format!("lifetime {} already in scope", name)); + err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name)); err.emit(); } diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs index 6c8965aa2e31f..bbbe568f17a8f 100644 --- a/compiler/rustc_serialize/src/json.rs +++ b/compiler/rustc_serialize/src/json.rs @@ -1859,7 +1859,7 @@ impl> Parser { } let n2 = self.decode_hex_escape()?; - if n2 < 0xDC00 || n2 > 0xDFFF { + if !(0xDC00..=0xDFFF).contains(&n2) { return self.error(LoneLeadingSurrogateInHexEscape); } let c = diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 66c709b408098..91ebc9a7c82e0 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -945,8 +945,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "instrument the generated code to support LLVM source-based code coverage \ reports (note, the compiler build config must include `profiler = true`, \ and is mutually exclusive with `-C profile-generate`/`-C profile-use`); \ - implies `-C link-dead-code` (unless targeting MSVC, or explicitly disabled) \ - and `-Z symbol-mangling-version=v0`; disables/overrides some Rust \ + implies `-Z symbol-mangling-version=v0`; disables/overrides some Rust \ optimizations (default: no)"), instrument_mcount: bool = (false, parse_bool, [TRACKED], "insert function instrument code for mcount-based tracing (default: no)"), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 5dddf0eb72ea6..4e269f3172c20 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1111,33 +1111,7 @@ impl Session { pub fn link_dead_code(&self) -> bool { match self.opts.cg.link_dead_code { Some(explicitly_set) => explicitly_set, - None => { - self.opts.debugging_opts.instrument_coverage && !self.target.is_like_msvc - // Issue #76038: (rustc `-Clink-dead-code` causes MSVC linker to produce invalid - // binaries when LLVM InstrProf counters are enabled). As described by this issue, - // the "link dead code" option produces incorrect binaries when compiled and linked - // under MSVC. The resulting Rust programs typically crash with a segmentation - // fault, or produce an empty "*.profraw" file (profiling counter results normally - // generated during program exit). - // - // If not targeting MSVC, `-Z instrument-coverage` implies `-C link-dead-code`, so - // unexecuted code is still counted as zero, rather than be optimized out. Note that - // instrumenting dead code can be explicitly disabled with: - // - // `-Z instrument-coverage -C link-dead-code=no`. - // - // FIXME(richkadel): Investigate if `instrument-coverage` implementation can inject - // [zero counters](https://llvm.org/docs/CoverageMappingFormat.html#counter) in the - // coverage map when "dead code" is removed, rather than forcing `link-dead-code`. - // This may not be possible, however, if (as it seems to appear) the "dead code" - // that would otherwise not be linked is only identified as "dead" by the native - // linker. If that's the case, I believe it is too late for the Rust compiler to - // leverage any information it might be able to get from the linker regarding what - // code is dead, to be able to add those counters. - // - // On the other hand, if any Rust compiler passes are optimizing out dead code blocks - // we should inject "zero" counters for those code regions. - } + None => false, } } @@ -1338,7 +1312,7 @@ pub fn build_session( let profiler = SelfProfiler::new( directory, - sopts.crate_name.as_ref().map(|s| &s[..]), + sopts.crate_name.as_deref(), &sopts.debugging_opts.self_profile_events, ); match profiler { diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index b4beb3dc37689..5987fb2a19897 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -97,7 +97,7 @@ cfg_if::cfg_if! { let ptr = src_bytes.as_ptr() as *const __m128i; // We don't know if the pointer is aligned to 16 bytes, so we // use `loadu`, which supports unaligned loading. - let chunk = _mm_loadu_si128(ptr.offset(chunk_index as isize)); + let chunk = _mm_loadu_si128(ptr.add(chunk_index)); // For character in the chunk, see if its byte value is < 0, which // indicates that it's part of a UTF-8 char. @@ -253,7 +253,7 @@ fn analyze_source_file_generic( let pos = BytePos::from_usize(i) + output_offset; if char_len > 1 { - assert!(char_len >= 2 && char_len <= 4); + assert!((2..=4).contains(&char_len)); let mbc = MultiByteChar { pos, bytes: char_len as u8 }; multi_byte_chars.push(mbc); } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 11a49d1ab887d..f63a73acbf4ba 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1015,10 +1015,7 @@ pub enum ExternalSourceKind { impl ExternalSource { pub fn is_absent(&self) -> bool { - match self { - ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. } => false, - _ => true, - } + !matches!(self, ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. }) } pub fn get_source(&self) -> Option<&Lrc> { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index f067cdb730864..e9b4eb6e4abe0 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -623,7 +623,7 @@ impl SourceMap { self.span_to_source(sp, |src, start_index, end_index| { src.get(start_index..end_index) .map(|s| s.to_string()) - .ok_or_else(|| SpanSnippetError::IllFormedSpan(sp)) + .ok_or(SpanSnippetError::IllFormedSpan(sp)) }) } @@ -640,9 +640,7 @@ impl SourceMap { /// Returns the source snippet as `String` before the given `Span`. pub fn span_to_prev_source(&self, sp: Span) -> Result { self.span_to_source(sp, |src, start_index, _| { - src.get(..start_index) - .map(|s| s.to_string()) - .ok_or_else(|| SpanSnippetError::IllFormedSpan(sp)) + src.get(..start_index).map(|s| s.to_string()).ok_or(SpanSnippetError::IllFormedSpan(sp)) }) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 523628b70582f..e75ddb36ff876 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -356,6 +356,7 @@ symbols! { concat_idents, conservative_impl_trait, console, + const_allocate, const_compare_raw_pointers, const_constructor, const_eval_limit, @@ -1362,15 +1363,13 @@ impl fmt::Display for IdentPrinter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.is_raw { f.write_str("r#")?; - } else { - if self.symbol == kw::DollarCrate { - if let Some(span) = self.convert_dollar_crate { - let converted = span.ctxt().dollar_crate_name(); - if !converted.is_path_segment_keyword() { - f.write_str("::")?; - } - return fmt::Display::fmt(&converted, f); + } else if self.symbol == kw::DollarCrate { + if let Some(span) = self.convert_dollar_crate { + let converted = span.ctxt().dollar_crate_name(); + if !converted.is_path_segment_keyword() { + f.write_str("::")?; } + return fmt::Display::fmt(&converted, f); } } fmt::Display::fmt(&self.symbol, f) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index fe4127fd4d8b9..9feba7bfc492f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1310,10 +1310,20 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { return None; } } + if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative { + return None; + } Some(imp) }) .collect(), - None => all_impls.map(|def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect(), + None => all_impls + .filter_map(|def_id| { + if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative { + return None; + } + self.tcx.impl_trait_ref(def_id) + }) + .collect(), } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index d6048d092b116..2fb9b3cd5d305 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -65,8 +65,7 @@ pub use self::util::{ get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices, }; pub use self::util::{ - supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type, - SupertraitDefIds, Supertraits, + supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, }; pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext; diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 915a15fd245d8..7888cb1b9f599 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -49,10 +49,9 @@ pub trait AstConv<'tcx> { fn default_constness_for_trait_bounds(&self) -> Constness; - /// Returns predicates in scope of the form `X: Foo`, where `X` - /// is a type parameter `X` with the given id `def_id` and T - /// matches `assoc_name`. This is a subset of the full set of - /// predicates. + /// Returns predicates in scope of the form `X: Foo`, where `X` is + /// a type parameter `X` with the given id `def_id`. This is a + /// subset of the full set of predicates. /// /// This is used for one specific purpose: resolving "short-hand" /// associated type references like `T::Item`. In principle, we @@ -61,12 +60,7 @@ pub trait AstConv<'tcx> { /// but this can lead to cycle errors. The problem is that we have /// to do this resolution *in order to create the predicates in /// the first place*. Hence, we have this "special pass". - fn get_type_parameter_bounds( - &self, - span: Span, - def_id: DefId, - assoc_name: Ident, - ) -> ty::GenericPredicates<'tcx>; + fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx>; /// Returns the lifetime to use when a lifetime is omitted (and not elided). fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) @@ -768,7 +762,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Returns `true` if a bounds list includes `?Sized`. - pub fn is_unsized(&self, ast_bounds: &[&hir::GenericBound<'_>], span: Span) -> bool { + pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool { let tcx = self.tcx(); // Try to find an unbound in bounds. @@ -826,7 +820,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn add_bounds( &self, param_ty: Ty<'tcx>, - ast_bounds: &[&hir::GenericBound<'_>], + ast_bounds: &[hir::GenericBound<'_>], bounds: &mut Bounds<'tcx>, ) { let constness = self.default_constness_for_trait_bounds(); @@ -841,7 +835,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self .instantiate_lang_item_trait_ref( - *lang_item, *span, *hir_id, args, param_ty, bounds, + lang_item, span, hir_id, args, param_ty, bounds, ), hir::GenericBound::Outlives(ref l) => { bounds.region_bounds.push((self.ast_region_to_region(l, None), l.span)) @@ -872,42 +866,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ast_bounds: &[hir::GenericBound<'_>], sized_by_default: SizedByDefault, span: Span, - ) -> Bounds<'tcx> { - let ast_bounds: Vec<_> = ast_bounds.iter().collect(); - self.compute_bounds_inner(param_ty, &ast_bounds, sized_by_default, span) - } - - /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type - /// named `assoc_name` into ty::Bounds. Ignore the rest. - pub fn compute_bounds_that_match_assoc_type( - &self, - param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], - sized_by_default: SizedByDefault, - span: Span, - assoc_name: Ident, - ) -> Bounds<'tcx> { - let mut result = Vec::new(); - - for ast_bound in ast_bounds { - if let Some(trait_ref) = ast_bound.trait_ref() { - if let Some(trait_did) = trait_ref.trait_def_id() { - if self.tcx().trait_may_define_assoc_type(trait_did, assoc_name) { - result.push(ast_bound); - } - } - } - } - - self.compute_bounds_inner(param_ty, &result, sized_by_default, span) - } - - fn compute_bounds_inner( - &self, - param_ty: Ty<'tcx>, - ast_bounds: &[&hir::GenericBound<'_>], - sized_by_default: SizedByDefault, - span: Span, ) -> Bounds<'tcx> { let mut bounds = Bounds::default(); @@ -1077,8 +1035,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` // parameter to have a skipped binder. let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs); - let ast_bounds: Vec<_> = ast_bounds.iter().collect(); - self.add_bounds(param_ty, &ast_bounds, bounds); + self.add_bounds(param_ty, ast_bounds, bounds); } } Ok(()) @@ -1395,9 +1352,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty_param_def_id, assoc_name, span, ); - let predicates = &self - .get_type_parameter_bounds(span, ty_param_def_id.to_def_id(), assoc_name) - .predicates; + let predicates = + &self.get_type_parameter_bounds(span, ty_param_def_id.to_def_id()).predicates; debug!("find_bound_for_assoc_item: predicates={:#?}", predicates); @@ -1405,14 +1361,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let param_name = tcx.hir().ty_param_name(param_hir_id); self.one_bound_for_assoc_type( || { - traits::transitive_bounds_that_define_assoc_type( + traits::transitive_bounds( tcx, predicates.iter().filter_map(|(p, _)| { p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value) }), - assoc_name, ) - .into_iter() }, || param_name.to_string(), assoc_name, diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs index 683707470f406..497754f20e4c5 100644 --- a/compiler/rustc_typeck/src/bounds.rs +++ b/compiler/rustc_typeck/src/bounds.rs @@ -67,22 +67,18 @@ impl<'tcx> Bounds<'tcx> { sized_predicate .into_iter() + .chain(self.region_bounds.iter().map(|&(region_bound, span)| { + let outlives = ty::OutlivesPredicate(param_ty, region_bound); + (ty::Binder::bind(outlives).to_predicate(tcx), span) + })) + .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { + let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); + (predicate, span) + })) .chain( - self.region_bounds + self.projection_bounds .iter() - .map(|&(region_bound, span)| { - let outlives = ty::OutlivesPredicate(param_ty, region_bound); - (ty::Binder::bind(outlives).to_predicate(tcx), span) - }) - .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { - let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); - (predicate, span) - })) - .chain( - self.projection_bounds - .iter() - .map(|&(projection, span)| (projection.to_predicate(tcx), span)), - ), + .map(|&(projection, span)| (projection.to_predicate(tcx), span)), ) .collect() } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 20c639a003109..f635e0b6f931c 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -20,7 +20,6 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::Session; -use rustc_span::symbol::Ident; use rustc_span::{self, Span}; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; @@ -184,12 +183,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } } - fn get_type_parameter_bounds( - &self, - _: Span, - def_id: DefId, - _: Ident, - ) -> ty::GenericPredicates<'tcx> { + fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { let tcx = self.tcx; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let item_id = tcx.hir().ty_param_owner(hir_id); diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index f40a250200e4a..e2712a3033995 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -286,6 +286,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool) } + sym::const_allocate => { + (0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8)) + } + sym::ptr_offset_from => { (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize) } diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 39a79893b6441..891dd8b2f0228 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -765,13 +765,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ) }); - // It is illegal to invoke a method on a trait instance that - // refers to the `Self` type. An error will be reported by - // `enforce_object_limitations()` if the method refers to the - // `Self` type anywhere other than the receiver. Here, we use - // a substitution that replaces `Self` with the object type - // itself. Hence, a `&self` method will wind up with an - // argument type like `&Trait`. + // It is illegal to invoke a method on a trait instance that refers to + // the `Self` type. An [`ObjectSafetyViolation::SupertraitSelf`] error + // will be reported by `object_safety.rs` if the method refers to the + // `Self` type anywhere other than the receiver. Here, we use a + // substitution that replaces `Self` with the object type itself. Hence, + // a `&self` method will wind up with an argument type like `&Trait`. let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 019fa78fb1e0e..30b4682296c6a 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -202,7 +202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // inference algorithm will reject it). // Equate the type variables for the upvars with the actual types. - let final_upvar_tys = self.final_upvar_tys(closure_hir_id); + let final_upvar_tys = self.final_upvar_tys(closure_def_id); debug!( "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}", closure_hir_id, substs, final_upvar_tys @@ -222,36 +222,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Returns a list of `Ty`s for each upvar. - fn final_upvar_tys(&self, closure_id: hir::HirId) -> Vec> { + fn final_upvar_tys(&self, closure_id: DefId) -> Vec> { // Presently an unboxed closure type cannot "escape" out of a // function, so we will only encounter ones that originated in the // local crate or were inlined into it along with some function. // This may change if abstract return types of some sort are // implemented. let tcx = self.tcx; - let closure_def_id = tcx.hir().local_def_id(closure_id); self.typeck_results .borrow() - .closure_captures - .get(&closure_def_id.to_def_id()) - .iter() - .flat_map(|upvars| { - upvars.iter().map(|(&var_hir_id, _)| { - let upvar_ty = self.node_ty(var_hir_id); - let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id); - let capture = self.typeck_results.borrow().upvar_capture(upvar_id); - - debug!("var_id={:?} upvar_ty={:?} capture={:?}", var_hir_id, upvar_ty, capture); - - match capture { - ty::UpvarCapture::ByValue(_) => upvar_ty, - ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref( - borrow.region, - ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() }, - ), - } - }) + .closure_min_captures_flattened(closure_id) + .map(|captured_place| { + let upvar_ty = captured_place.place.ty(); + let capture = captured_place.info.capture_kind; + + debug!( + "place={:?} upvar_ty={:?} capture={:?}", + captured_place.place, upvar_ty, capture + ); + + match capture { + ty::UpvarCapture::ByValue(_) => upvar_ty, + ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref( + borrow.region, + ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() }, + ), + } }) .collect() } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index d1ada123c0d5a..7c9cfe69fc94b 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -55,6 +55,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (), } wbcx.visit_body(body); + wbcx.visit_min_capture_map(); wbcx.visit_upvar_capture_map(); wbcx.visit_closures(); wbcx.visit_liberated_fn_sigs(); @@ -88,7 +89,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /////////////////////////////////////////////////////////////////////////// -// The Writeback context. This visitor walks the AST, checking the +// The Writeback context. This visitor walks the HIR, checking the // fn-specific typeck results to find references to types or regions. It // resolves those regions to remove inference variables and writes the // final result back into the master typeck results in the tcx. Here and @@ -331,6 +332,37 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { } impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { + fn visit_min_capture_map(&mut self) { + let mut min_captures_wb = ty::MinCaptureInformationMap::with_capacity_and_hasher( + self.fcx.typeck_results.borrow().closure_min_captures.len(), + Default::default(), + ); + for (closure_def_id, root_min_captures) in + self.fcx.typeck_results.borrow().closure_min_captures.iter() + { + let mut root_var_map_wb = ty::RootVariableMinCaptureList::with_capacity_and_hasher( + root_min_captures.len(), + Default::default(), + ); + for (var_hir_id, min_list) in root_min_captures.iter() { + let min_list_wb = min_list + .iter() + .map(|captured_place| { + let locatable = captured_place.info.expr_id.unwrap_or( + self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local()), + ); + + self.resolve(captured_place.clone(), &locatable) + }) + .collect(); + root_var_map_wb.insert(*var_hir_id, min_list_wb); + } + min_captures_wb.insert(*closure_def_id, root_var_map_wb); + } + + self.typeck_results.closure_min_captures = min_captures_wb; + } + fn visit_upvar_capture_map(&mut self) { for (upvar_id, upvar_capture) in self.fcx.typeck_results.borrow().upvar_capture_map.iter() { let new_upvar_capture = match *upvar_capture { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index f8b7ccb2cd618..0ff10abb60a35 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1,4 +1,3 @@ -// ignore-tidy-filelength //! "Collection" is the process of determining the type and other external //! details of each item in Rust. Collection is specifically concerned //! with *inter-procedural* things -- for example, for a function @@ -80,7 +79,6 @@ pub fn provide(providers: &mut Providers) { projection_ty_from_predicates, explicit_predicates_of, super_predicates_of, - super_predicates_that_define_assoc_type, trait_explicit_predicates_and_bounds, type_param_predicates, trait_def, @@ -312,17 +310,8 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { } } - fn get_type_parameter_bounds( - &self, - span: Span, - def_id: DefId, - assoc_name: Ident, - ) -> ty::GenericPredicates<'tcx> { - self.tcx.at(span).type_param_predicates(( - self.item_def_id, - def_id.expect_local(), - assoc_name, - )) + fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { + self.tcx.at(span).type_param_predicates((self.item_def_id, def_id.expect_local())) } fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option> { @@ -503,7 +492,7 @@ fn get_new_lifetime_name<'tcx>( /// `X: Foo` where `X` is the type parameter `def_id`. fn type_param_predicates( tcx: TyCtxt<'_>, - (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident), + (item_def_id, def_id): (DefId, LocalDefId), ) -> ty::GenericPredicates<'_> { use rustc_hir::*; @@ -528,7 +517,7 @@ fn type_param_predicates( let mut result = parent .map(|parent| { let icx = ItemCtxt::new(tcx, parent); - icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name) + icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id()) }) .unwrap_or_default(); let mut extend = None; @@ -571,18 +560,12 @@ fn type_param_predicates( let icx = ItemCtxt::new(tcx, item_def_id); let extra_predicates = extend.into_iter().chain( - icx.type_parameter_bounds_in_generics( - ast_generics, - param_id, - ty, - OnlySelfBounds(true), - Some(assoc_name), - ) - .into_iter() - .filter(|(predicate, _)| match predicate.skip_binders() { - ty::PredicateAtom::Trait(data, _) => data.self_ty().is_param(index), - _ => false, - }), + icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true)) + .into_iter() + .filter(|(predicate, _)| match predicate.skip_binders() { + ty::PredicateAtom::Trait(data, _) => data.self_ty().is_param(index), + _ => false, + }), ); result.predicates = tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates)); @@ -600,7 +583,6 @@ impl ItemCtxt<'tcx> { param_id: hir::HirId, ty: Ty<'tcx>, only_self_bounds: OnlySelfBounds, - assoc_name: Option, ) -> Vec<(ty::Predicate<'tcx>, Span)> { let constness = self.default_constness_for_trait_bounds(); let from_ty_params = ast_generics @@ -611,10 +593,6 @@ impl ItemCtxt<'tcx> { _ => None, }) .flat_map(|bounds| bounds.iter()) - .filter(|b| match assoc_name { - Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name), - None => true, - }) .flat_map(|b| predicates_from_bound(self, ty, b, constness)); let from_where_clauses = ast_generics @@ -633,34 +611,12 @@ impl ItemCtxt<'tcx> { } else { None }; - bp.bounds - .iter() - .filter(|b| match assoc_name { - Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name), - None => true, - }) - .filter_map(move |b| bt.map(|bt| (bt, b))) + bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b))) }) .flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness)); from_ty_params.chain(from_where_clauses).collect() } - - fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool { - debug!("bound_defines_assoc_item(b={:?}, assoc_name={:?})", b, assoc_name); - - match b { - hir::GenericBound::Trait(poly_trait_ref, _) => { - let trait_ref = &poly_trait_ref.trait_ref; - if let Some(trait_did) = trait_ref.trait_def_id() { - self.tcx.trait_may_define_assoc_type(trait_did, assoc_name) - } else { - false - } - } - _ => false, - } - } } /// Tests whether this is the AST for a reference to the type @@ -1029,90 +985,54 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AdtDef { /// the transitive super-predicates are converted. fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredicates<'_> { debug!("super_predicates(trait_def_id={:?})", trait_def_id); - tcx.super_predicates_that_define_assoc_type((trait_def_id, None)) -} - -/// Ensures that the super-predicates of the trait with a `DefId` -/// of `trait_def_id` are converted and stored. This also ensures that -/// the transitive super-predicates are converted. -fn super_predicates_that_define_assoc_type( - tcx: TyCtxt<'_>, - (trait_def_id, assoc_name): (DefId, Option), -) -> ty::GenericPredicates<'_> { - debug!( - "super_predicates_that_define_assoc_type(trait_def_id={:?}, assoc_name={:?})", - trait_def_id, assoc_name - ); - if trait_def_id.is_local() { - debug!("super_predicates_that_define_assoc_type: local trait_def_id={:?}", trait_def_id); - let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local()); - - let item = match tcx.hir().get(trait_hir_id) { - Node::Item(item) => item, - _ => bug!("trait_node_id {} is not an item", trait_hir_id), - }; + let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local()); - let (generics, bounds) = match item.kind { - hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits), - _ => span_bug!(item.span, "super_predicates invoked on non-trait"), - }; - - let icx = ItemCtxt::new(tcx, trait_def_id); + let item = match tcx.hir().get(trait_hir_id) { + Node::Item(item) => item, + _ => bug!("trait_node_id {} is not an item", trait_hir_id), + }; - // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. - let self_param_ty = tcx.types.self_param; - let superbounds1 = if let Some(assoc_name) = assoc_name { - AstConv::compute_bounds_that_match_assoc_type( - &icx, - self_param_ty, - &bounds, - SizedByDefault::No, - item.span, - assoc_name, - ) - } else { - AstConv::compute_bounds(&icx, self_param_ty, &bounds, SizedByDefault::No, item.span) - }; + let (generics, bounds) = match item.kind { + hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits), + hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits), + _ => span_bug!(item.span, "super_predicates invoked on non-trait"), + }; - let superbounds1 = superbounds1.predicates(tcx, self_param_ty); + let icx = ItemCtxt::new(tcx, trait_def_id); + + // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. + let self_param_ty = tcx.types.self_param; + let superbounds1 = + AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span); + + let superbounds1 = superbounds1.predicates(tcx, self_param_ty); + + // Convert any explicit superbounds in the where-clause, + // e.g., `trait Foo where Self: Bar`. + // In the case of trait aliases, however, we include all bounds in the where-clause, + // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` + // as one of its "superpredicates". + let is_trait_alias = tcx.is_trait_alias(trait_def_id); + let superbounds2 = icx.type_parameter_bounds_in_generics( + generics, + item.hir_id, + self_param_ty, + OnlySelfBounds(!is_trait_alias), + ); - // Convert any explicit superbounds in the where-clause, - // e.g., `trait Foo where Self: Bar`. - // In the case of trait aliases, however, we include all bounds in the where-clause, - // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` - // as one of its "superpredicates". - let is_trait_alias = tcx.is_trait_alias(trait_def_id); - let superbounds2 = icx.type_parameter_bounds_in_generics( - generics, - item.hir_id, - self_param_ty, - OnlySelfBounds(!is_trait_alias), - assoc_name, - ); + // Combine the two lists to form the complete set of superbounds: + let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2)); - // Combine the two lists to form the complete set of superbounds: - let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2)); - - // Now require that immediate supertraits are converted, - // which will, in turn, reach indirect supertraits. - if assoc_name.is_none() { - // FIXME: move this into the `super_predicates_of` query - for &(pred, span) in superbounds { - debug!("superbound: {:?}", pred); - if let ty::PredicateAtom::Trait(bound, _) = pred.skip_binders() { - tcx.at(span).super_predicates_of(bound.def_id()); - } - } + // Now require that immediate supertraits are converted, + // which will, in turn, reach indirect supertraits. + for &(pred, span) in superbounds { + debug!("superbound: {:?}", pred); + if let ty::PredicateAtom::Trait(bound, _) = pred.skip_binders() { + tcx.at(span).super_predicates_of(bound.def_id()); } - - ty::GenericPredicates { parent: None, predicates: superbounds } - } else { - // if `assoc_name` is None, then the query should've been redirected to an - // external provider - assert!(assoc_name.is_some()); - tcx.super_predicates_of(trait_def_id) } + + ty::GenericPredicates { parent: None, predicates: superbounds } } fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index dd1da7d9cff2d..e596dd1a396c9 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -28,7 +28,7 @@ fn associated_type_bounds<'tcx>( let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, assoc_item_def_id), item_ty, - &bounds, + bounds, SizedByDefault::Yes, span, ); @@ -68,7 +68,7 @@ fn opaque_type_bounds<'tcx>( let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, opaque_def_id), item_ty, - &bounds, + bounds, SizedByDefault::Yes, span, ) diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 1b51d5e0182fd..8a324807417da 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -15,7 +15,6 @@ use rustc_index::vec::Idx; use rustc_infer::infer::InferCtxt; use rustc_middle::hir::place::ProjectionKind; use rustc_middle::ty::{self, adjustment, TyCtxt}; -use rustc_span::Span; use rustc_target::abi::VariantIdx; use crate::mem_categorization as mc; @@ -571,38 +570,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { })); } - /// Walk closure captures but using `closure_caputes` instead - /// of `closure_min_captures`. - /// - /// This is needed because clippy uses `ExprUseVisitor` after TypeckResults - /// are written back. We don't currently writeback min_captures to - /// TypeckResults. - fn walk_captures_closure_captures(&mut self, closure_expr: &hir::Expr<'_>) { - // FIXME(arora-aman): Remove this function once rust-lang/project-rfc-2229#18 - // is completed. - debug!("walk_captures_closure_captures({:?}), ", closure_expr); - - let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id(); - let cl_span = self.tcx().hir().span(closure_expr.hir_id); - - let captures = &self.mc.typeck_results.closure_captures[&closure_def_id]; - - for (&var_id, &upvar_id) in captures { - let upvar_capture = self.mc.typeck_results.upvar_capture(upvar_id); - let captured_place = - return_if_err!(self.cat_captured_var(closure_expr.hir_id, cl_span, var_id)); - match upvar_capture { - ty::UpvarCapture::ByValue(_) => { - let mode = copy_or_move(&self.mc, &captured_place); - self.delegate.consume(&captured_place, captured_place.hir_id, mode); - } - ty::UpvarCapture::ByRef(upvar_borrow) => { - self.delegate.borrow(&captured_place, captured_place.hir_id, upvar_borrow.kind); - } - } - } - } - /// Handle the case where the current body contains a closure. /// /// When the current body being handled is a closure, then we must make sure that @@ -646,16 +613,18 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let place = &captured_place.place; let capture_info = captured_place.info; - let upvar_id = if body_owner_is_closure { + let place_base = if body_owner_is_closure { // Mark the place to be captured by the enclosing closure - ty::UpvarId::new(*var_hir_id, self.body_owner) + PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.body_owner)) } else { - ty::UpvarId::new(*var_hir_id, closure_def_id.expect_local()) + // If the body owner isn't a closure then the variable must + // be a local variable + PlaceBase::Local(*var_hir_id) }; let place_with_id = PlaceWithHirId::new( capture_info.expr_id.unwrap_or(closure_expr.hir_id), place.base_ty, - PlaceBase::Upvar(upvar_id), + place_base, place.projections.clone(), ); @@ -674,23 +643,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } } - } else if self.mc.typeck_results.closure_captures.contains_key(&closure_def_id) { - // Handle the case where clippy calls ExprUseVisitor after - self.walk_captures_closure_captures(closure_expr) } } - - fn cat_captured_var( - &mut self, - closure_hir_id: hir::HirId, - closure_span: Span, - var_id: hir::HirId, - ) -> mc::McResult> { - // Create the place for the variable being borrowed, from the - // perspective of the creator (parent) of the closure. - let var_ty = self.mc.node_ty(var_id)?; - self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(var_id)) - } } fn copy_or_move<'a, 'tcx>( diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index b1bfc2abe44ac..4fbcc4590f1a9 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -38,7 +38,7 @@ extern "Rust" { /// The global memory allocator. /// -/// This type implements the [`AllocRef`] trait by forwarding calls +/// This type implements the [`Allocator`] trait by forwarding calls /// to the allocator registered with the `#[global_allocator]` attribute /// if there is one, or the `std` crate’s default. /// @@ -59,7 +59,7 @@ pub use std::alloc::Global; /// if there is one, or the `std` crate’s default. /// /// This function is expected to be deprecated in favor of the `alloc` method -/// of the [`Global`] type when it and the [`AllocRef`] trait become stable. +/// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety /// @@ -93,7 +93,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { /// if there is one, or the `std` crate’s default. /// /// This function is expected to be deprecated in favor of the `dealloc` method -/// of the [`Global`] type when it and the [`AllocRef`] trait become stable. +/// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety /// @@ -111,7 +111,7 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { /// if there is one, or the `std` crate’s default. /// /// This function is expected to be deprecated in favor of the `realloc` method -/// of the [`Global`] type when it and the [`AllocRef`] trait become stable. +/// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety /// @@ -129,7 +129,7 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 /// if there is one, or the `std` crate’s default. /// /// This function is expected to be deprecated in favor of the `alloc_zeroed` method -/// of the [`Global`] type when it and the [`AllocRef`] trait become stable. +/// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety /// @@ -170,7 +170,7 @@ impl Global { } } - // SAFETY: Same as `AllocRef::grow` + // SAFETY: Same as `Allocator::grow` #[inline] unsafe fn grow_impl( &self, @@ -211,7 +211,7 @@ impl Global { old_size => unsafe { let new_ptr = self.alloc_impl(new_layout, zeroed)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); Ok(new_ptr) }, } @@ -220,19 +220,19 @@ impl Global { #[unstable(feature = "allocator_api", issue = "32838")] #[cfg(not(test))] -unsafe impl AllocRef for Global { +unsafe impl Allocator for Global { #[inline] - fn alloc(&self, layout: Layout) -> Result, AllocError> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, false) } #[inline] - fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, true) } #[inline] - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller @@ -277,7 +277,7 @@ unsafe impl AllocRef for Global { match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, @@ -297,9 +297,9 @@ unsafe impl AllocRef for Global { // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // for `dealloc` must be upheld by the caller. new_size => unsafe { - let new_ptr = self.alloc(new_layout)?; + let new_ptr = self.allocate(new_layout)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); Ok(new_ptr) }, } @@ -313,7 +313,7 @@ unsafe impl AllocRef for Global { #[inline] unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; - match Global.alloc(layout) { + match Global.allocate(layout) { Ok(ptr) => ptr.as_mut_ptr(), Err(_) => handle_alloc_error(layout), } @@ -322,16 +322,16 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { #[cfg_attr(not(test), lang = "box_free")] #[inline] // This signature has to be the same as `Box`, otherwise an ICE will happen. -// When an additional parameter to `Box` is added (like `A: AllocRef`), this has to be added here as +// When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as // well. -// For example if `Box` is changed to `struct Box(Unique, A)`, -// this function has to be changed to `fn box_free(Unique, A)` as well. -pub(crate) unsafe fn box_free(ptr: Unique, alloc: A) { +// For example if `Box` is changed to `struct Box(Unique, A)`, +// this function has to be changed to `fn box_free(Unique, A)` as well. +pub(crate) unsafe fn box_free(ptr: Unique, alloc: A) { unsafe { let size = size_of_val(ptr.as_ref()); let align = min_align_of_val(ptr.as_ref()); let layout = Layout::from_size_align_unchecked(size, align); - alloc.dealloc(ptr.cast().into(), layout) + alloc.deallocate(ptr.cast().into(), layout) } } diff --git a/library/alloc/src/alloc/tests.rs b/library/alloc/src/alloc/tests.rs index f7463d0daac93..94e05fa448f86 100644 --- a/library/alloc/src/alloc/tests.rs +++ b/library/alloc/src/alloc/tests.rs @@ -9,7 +9,7 @@ fn allocate_zeroed() { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); let ptr = - Global.alloc_zeroed(layout.clone()).unwrap_or_else(|_| handle_alloc_error(layout)); + Global.allocate_zeroed(layout.clone()).unwrap_or_else(|_| handle_alloc_error(layout)); let mut i = ptr.as_non_null_ptr().as_ptr(); let end = i.add(layout.size()); @@ -17,7 +17,7 @@ fn allocate_zeroed() { assert_eq!(*i, 0); i = i.offset(1); } - Global.dealloc(ptr.as_non_null_ptr(), layout); + Global.deallocate(ptr.as_non_null_ptr(), layout); } } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index d814c525ceb6e..a6360f25eca31 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -153,7 +153,7 @@ use core::pin::Pin; use core::ptr::{self, Unique}; use core::task::{Context, Poll}; -use crate::alloc::{handle_alloc_error, AllocRef, Global, Layout}; +use crate::alloc::{handle_alloc_error, Allocator, Global, Layout}; use crate::borrow::Cow; use crate::raw_vec::RawVec; use crate::str::from_boxed_utf8_unchecked; @@ -167,7 +167,7 @@ use crate::vec::Vec; #[stable(feature = "rust1", since = "1.0.0")] pub struct Box< T: ?Sized, - #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, >(Unique, A); impl Box { @@ -243,7 +243,7 @@ impl Box { } } -impl Box { +impl Box { /// Allocates memory in the given allocator then places `x` into it. /// /// This doesn't actually allocate if `T` is zero-sized. @@ -291,7 +291,7 @@ impl Box { // #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_uninit_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); - let ptr = alloc.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)).cast(); + let ptr = alloc.allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)).cast(); unsafe { Box::from_raw_in(ptr.as_ptr(), alloc) } } @@ -319,7 +319,8 @@ impl Box { // #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); - let ptr = alloc.alloc_zeroed(layout).unwrap_or_else(|_| handle_alloc_error(layout)).cast(); + let ptr = + alloc.allocate_zeroed(layout).unwrap_or_else(|_| handle_alloc_error(layout)).cast(); unsafe { Box::from_raw_in(ptr.as_ptr(), alloc) } } @@ -339,7 +340,7 @@ impl Box { /// This conversion does not allocate on the heap and happens in place. #[unstable(feature = "box_into_boxed_slice", issue = "71582")] pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> { - let (raw, alloc) = Box::into_raw_with_alloc(boxed); + let (raw, alloc) = Box::into_raw_with_allocator(boxed); unsafe { Box::from_raw_in(raw as *mut [T; 1], alloc) } } } @@ -394,7 +395,7 @@ impl Box<[T]> { } } -impl Box<[T], A> { +impl Box<[T], A> { /// Constructs a new boxed slice with uninitialized contents in the provided allocator. /// /// # Examples @@ -450,7 +451,7 @@ impl Box<[T], A> { } } -impl Box, A> { +impl Box, A> { /// Converts to `Box`. /// /// # Safety @@ -482,12 +483,12 @@ impl Box, A> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Box { - let (raw, alloc) = Box::into_raw_with_alloc(self); + let (raw, alloc) = Box::into_raw_with_allocator(self); unsafe { Box::from_raw_in(raw as *mut T, alloc) } } } -impl Box<[mem::MaybeUninit], A> { +impl Box<[mem::MaybeUninit], A> { /// Converts to `Box<[T], A>`. /// /// # Safety @@ -521,7 +522,7 @@ impl Box<[mem::MaybeUninit], A> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Box<[T], A> { - let (raw, alloc) = Box::into_raw_with_alloc(self); + let (raw, alloc) = Box::into_raw_with_allocator(self); unsafe { Box::from_raw_in(raw as *mut [T], alloc) } } } @@ -575,7 +576,7 @@ impl Box { } } -impl Box { +impl Box { /// Constructs a box from a raw pointer in the given allocator. /// /// After calling this function, the raw pointer is owned by the @@ -594,24 +595,24 @@ impl Box { /// # Examples /// /// Recreate a `Box` which was previously converted to a raw pointer - /// using [`Box::into_raw_with_alloc`]: + /// using [`Box::into_raw_with_allocator`]: /// ``` /// #![feature(allocator_api)] /// /// use std::alloc::System; /// /// let x = Box::new_in(5, System); - /// let (ptr, alloc) = Box::into_raw_with_alloc(x); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; /// ``` /// Manually create a `Box` from scratch by using the system allocator: /// ``` /// #![feature(allocator_api, slice_ptr_get)] /// - /// use std::alloc::{AllocRef, Layout, System}; + /// use std::alloc::{Allocator, Layout, System}; /// /// unsafe { - /// let ptr = System.alloc(Layout::new::())?.as_mut_ptr(); + /// let ptr = System.allocate(Layout::new::())?.as_mut_ptr(); /// // In general .write is required to avoid attempting to destruct /// // the (uninitialized) previous contents of `ptr`, though for this /// // simple example `*ptr = 5` would have worked as well. @@ -671,7 +672,7 @@ impl Box { #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub fn into_raw(b: Self) -> *mut T { - Self::into_raw_with_alloc(b).0 + Self::into_raw_with_allocator(b).0 } /// Consumes the `Box`, returning a wrapped raw pointer and the allocator. @@ -687,7 +688,7 @@ impl Box { /// the cleanup. /// /// Note: this is an associated function, which means that you have - /// to call it as `Box::into_raw_with_alloc(b)` instead of `b.into_raw_with_alloc()`. This + /// to call it as `Box::into_raw_with_allocator(b)` instead of `b.into_raw_with_allocator()`. This /// is so that there is no conflict with a method on the inner type. /// /// # Examples @@ -699,7 +700,7 @@ impl Box { /// use std::alloc::System; /// /// let x = Box::new_in(String::from("Hello"), System); - /// let (ptr, alloc) = Box::into_raw_with_alloc(x); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; /// ``` /// Manual cleanup by explicitly running the destructor and deallocating @@ -707,22 +708,22 @@ impl Box { /// ``` /// #![feature(allocator_api)] /// - /// use std::alloc::{AllocRef, Layout, System}; + /// use std::alloc::{Allocator, Layout, System}; /// use std::ptr::{self, NonNull}; /// /// let x = Box::new_in(String::from("Hello"), System); - /// let (ptr, alloc) = Box::into_raw_with_alloc(x); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); /// unsafe { /// ptr::drop_in_place(ptr); /// let non_null = NonNull::new_unchecked(ptr); - /// alloc.dealloc(non_null.cast(), Layout::new::()); + /// alloc.deallocate(non_null.cast(), Layout::new::()); /// } /// ``` /// /// [memory layout]: self#memory-layout #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn into_raw_with_alloc(b: Self) -> (*mut T, A) { + pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) { let (leaked, alloc) = Box::into_unique(b); (leaked.as_ptr(), alloc) } @@ -747,11 +748,11 @@ impl Box { /// Returns a reference to the underlying allocator. /// /// Note: this is an associated function, which means that you have - /// to call it as `Box::alloc_ref(&b)` instead of `b.alloc_ref()`. This + /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This /// is so that there is no conflict with a method on the inner type. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn alloc_ref(b: &Self) -> &A { + pub fn allocator(b: &Self) -> &A { &b.1 } @@ -817,7 +818,7 @@ impl Box { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized, A: AllocRef> Drop for Box { +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { fn drop(&mut self) { // FIXME: Do nothing, drop is currently performed by compiler. } @@ -846,7 +847,7 @@ impl Default for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Box { +impl Clone for Box { /// Returns a new box with a `clone()` of this box's contents. /// /// # Examples @@ -900,7 +901,7 @@ impl Clone for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Box { +impl PartialEq for Box { #[inline] fn eq(&self, other: &Self) -> bool { PartialEq::eq(&**self, &**other) @@ -911,7 +912,7 @@ impl PartialEq for Box { } } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Box { +impl PartialOrd for Box { #[inline] fn partial_cmp(&self, other: &Self) -> Option { PartialOrd::partial_cmp(&**self, &**other) @@ -934,24 +935,24 @@ impl PartialOrd for Box { } } #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Box { +impl Ord for Box { #[inline] fn cmp(&self, other: &Self) -> Ordering { Ord::cmp(&**self, &**other) } } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Box {} +impl Eq for Box {} #[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Box { +impl Hash for Box { fn hash(&self, state: &mut H) { (**self).hash(state); } } #[stable(feature = "indirect_hasher_impl", since = "1.22.0")] -impl Hasher for Box { +impl Hasher for Box { fn finish(&self) -> u64 { (**self).finish() } @@ -1016,7 +1017,7 @@ impl From for Box { } #[stable(feature = "pin", since = "1.33.0")] -impl From> for Pin> +impl From> for Pin> where A: 'static, { @@ -1094,7 +1095,7 @@ impl From> for Box { } #[stable(feature = "boxed_str_conv", since = "1.19.0")] -impl From> for Box<[u8], A> { +impl From> for Box<[u8], A> { /// Converts a `Box` into a `Box<[u8]>` /// /// This conversion does not allocate on the heap and happens in place. @@ -1113,7 +1114,7 @@ impl From> for Box<[u8], A> { /// ``` #[inline] fn from(s: Box) -> Self { - let (raw, alloc) = Box::into_raw_with_alloc(s); + let (raw, alloc) = Box::into_raw_with_allocator(s); unsafe { Box::from_raw_in(raw as *mut [u8], alloc) } } } @@ -1147,7 +1148,7 @@ impl TryFrom> for Box<[T; N]> { } } -impl Box { +impl Box { #[inline] #[stable(feature = "rust1", since = "1.0.0")] /// Attempt to downcast the box to a concrete type. @@ -1170,7 +1171,7 @@ impl Box { pub fn downcast(self) -> Result, Self> { if self.is::() { unsafe { - let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_alloc(self); + let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self); Ok(Box::from_raw_in(raw as *mut T, alloc)) } } else { @@ -1179,7 +1180,7 @@ impl Box { } } -impl Box { +impl Box { #[inline] #[stable(feature = "rust1", since = "1.0.0")] /// Attempt to downcast the box to a concrete type. @@ -1202,7 +1203,7 @@ impl Box { pub fn downcast(self) -> Result, Self> { if self.is::() { unsafe { - let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_alloc(self); + let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self); Ok(Box::from_raw_in(raw as *mut T, alloc)) } } else { @@ -1212,21 +1213,21 @@ impl Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Box { +impl fmt::Display for Box { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Box { +impl fmt::Debug for Box { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Pointer for Box { +impl fmt::Pointer for Box { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // It's not possible to extract the inner Uniq directly from the Box, // instead we cast it to a *const which aliases the Unique @@ -1236,7 +1237,7 @@ impl fmt::Pointer for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl Deref for Box { +impl Deref for Box { type Target = T; fn deref(&self) -> &T { @@ -1245,17 +1246,17 @@ impl Deref for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl DerefMut for Box { +impl DerefMut for Box { fn deref_mut(&mut self) -> &mut T { &mut **self } } #[unstable(feature = "receiver_trait", issue = "none")] -impl Receiver for Box {} +impl Receiver for Box {} #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Box { +impl Iterator for Box { type Item = I::Item; fn next(&mut self) -> Option { (**self).next() @@ -1276,7 +1277,7 @@ trait BoxIter { fn last(self) -> Option; } -impl BoxIter for Box { +impl BoxIter for Box { type Item = I::Item; default fn last(self) -> Option { #[inline] @@ -1291,14 +1292,14 @@ impl BoxIter for Box { /// Specialization for sized `I`s that uses `I`s implementation of `last()` /// instead of the default. #[stable(feature = "rust1", since = "1.0.0")] -impl BoxIter for Box { +impl BoxIter for Box { fn last(self) -> Option { (*self).last() } } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Box { +impl DoubleEndedIterator for Box { fn next_back(&mut self) -> Option { (**self).next_back() } @@ -1307,7 +1308,7 @@ impl DoubleEndedIterator for Box ExactSizeIterator for Box { +impl ExactSizeIterator for Box { fn len(&self) -> usize { (**self).len() } @@ -1317,10 +1318,10 @@ impl ExactSizeIterator for Box } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Box {} +impl FusedIterator for Box {} #[stable(feature = "boxed_closure_impls", since = "1.35.0")] -impl + ?Sized, A: AllocRef> FnOnce for Box { +impl + ?Sized, A: Allocator> FnOnce for Box { type Output = >::Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output { @@ -1329,21 +1330,21 @@ impl + ?Sized, A: AllocRef> FnOnce for Box { } #[stable(feature = "boxed_closure_impls", since = "1.35.0")] -impl + ?Sized, A: AllocRef> FnMut for Box { +impl + ?Sized, A: Allocator> FnMut for Box { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output { >::call_mut(self, args) } } #[stable(feature = "boxed_closure_impls", since = "1.35.0")] -impl + ?Sized, A: AllocRef> Fn for Box { +impl + ?Sized, A: Allocator> Fn for Box { extern "rust-call" fn call(&self, args: Args) -> Self::Output { >::call(self, args) } } #[unstable(feature = "coerce_unsized", issue = "27732")] -impl, U: ?Sized, A: AllocRef> CoerceUnsized> for Box {} +impl, U: ?Sized, A: Allocator> CoerceUnsized> for Box {} #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl, U: ?Sized> DispatchFromDyn> for Box {} @@ -1356,9 +1357,9 @@ impl FromIterator for Box<[I]> { } #[stable(feature = "box_slice_clone", since = "1.3.0")] -impl Clone for Box<[T], A> { +impl Clone for Box<[T], A> { fn clone(&self) -> Self { - let alloc = Box::alloc_ref(self).clone(); + let alloc = Box::allocator(self).clone(); self.to_vec_in(alloc).into_boxed_slice() } @@ -1372,28 +1373,28 @@ impl Clone for Box<[T], A> { } #[stable(feature = "box_borrow", since = "1.1.0")] -impl borrow::Borrow for Box { +impl borrow::Borrow for Box { fn borrow(&self) -> &T { &**self } } #[stable(feature = "box_borrow", since = "1.1.0")] -impl borrow::BorrowMut for Box { +impl borrow::BorrowMut for Box { fn borrow_mut(&mut self) -> &mut T { &mut **self } } #[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] -impl AsRef for Box { +impl AsRef for Box { fn as_ref(&self) -> &T { &**self } } #[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] -impl AsMut for Box { +impl AsMut for Box { fn as_mut(&mut self) -> &mut T { &mut **self } @@ -1422,10 +1423,10 @@ impl AsMut for Box { * could have a method to project a Pin from it. */ #[stable(feature = "pin", since = "1.33.0")] -impl Unpin for Box where A: 'static {} +impl Unpin for Box where A: 'static {} #[unstable(feature = "generator_trait", issue = "43122")] -impl + Unpin, R, A: AllocRef> Generator for Box +impl + Unpin, R, A: Allocator> Generator for Box where A: 'static, { @@ -1438,7 +1439,7 @@ where } #[unstable(feature = "generator_trait", issue = "43122")] -impl, R, A: AllocRef> Generator for Pin> +impl, R, A: Allocator> Generator for Pin> where A: 'static, { @@ -1451,7 +1452,7 @@ where } #[stable(feature = "futures_api", since = "1.36.0")] -impl Future for Box +impl Future for Box where A: 'static, { diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 23cd4f3d83d62..97df8ea07d23e 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1772,7 +1772,7 @@ fn test_append_drop_leak() { catch_unwind(move || left.append(&mut right)).unwrap_err(); - assert_eq!(DROPS.load(SeqCst), 4); // Rust issue #47949 ate one little piggy + assert_eq!(DROPS.load(SeqCst), 5); } #[test] diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 78be070a98382..31809fde57b7a 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -36,7 +36,7 @@ use core::marker::PhantomData; use core::mem::{self, MaybeUninit}; use core::ptr::{self, NonNull}; -use crate::alloc::{AllocRef, Global, Layout}; +use crate::alloc::{Allocator, Global, Layout}; use crate::boxed::Box; const B: usize = 6; @@ -195,7 +195,7 @@ impl NodeRef { self.borrow_mut().clear_parent_link(); unsafe { - Global.dealloc(top.cast(), Layout::new::>()); + Global.deallocate(top.cast(), Layout::new::>()); } } } @@ -449,7 +449,7 @@ impl NodeRef { let node = self.node; let ret = self.ascend().ok(); unsafe { - Global.dealloc( + Global.deallocate( node.cast(), if height > 0 { Layout::new::>() @@ -1407,9 +1407,9 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { left_node.correct_childrens_parent_links(left_len + 1..=left_len + 1 + right_len); - Global.dealloc(right_node.node.cast(), Layout::new::>()); + Global.deallocate(right_node.node.cast(), Layout::new::>()); } else { - Global.dealloc(right_node.node.cast(), Layout::new::>()); + Global.deallocate(right_node.node.cast(), Layout::new::>()); } let new_idx = match track_edge_idx { diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index edab576bea8dd..edee439ad8dfa 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -9,7 +9,7 @@ use core::ops::Drop; use core::ptr::{self, NonNull, Unique}; use core::slice; -use crate::alloc::{handle_alloc_error, AllocRef, Global, Layout}; +use crate::alloc::{handle_alloc_error, Allocator, Global, Layout}; use crate::boxed::Box; use crate::collections::TryReserveError::{self, *}; @@ -46,7 +46,7 @@ enum AllocInit { /// `usize::MAX`. This means that you need to be careful when round-tripping this type with a /// `Box<[T]>`, since `capacity()` won't yield the length. #[allow(missing_debug_implementations)] -pub struct RawVec { +pub struct RawVec { ptr: Unique, cap: usize, alloc: A, @@ -113,7 +113,7 @@ impl RawVec { } } -impl RawVec { +impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. #[rustc_allow_const_fn_unstable(const_fn)] @@ -139,7 +139,7 @@ impl RawVec { /// Converts a `Box<[T]>` into a `RawVec`. pub fn from_box(slice: Box<[T], A>) -> Self { unsafe { - let (slice, alloc) = Box::into_raw_with_alloc(slice); + let (slice, alloc) = Box::into_raw_with_allocator(slice); RawVec::from_raw_parts_in(slice.as_mut_ptr(), slice.len(), alloc) } } @@ -185,8 +185,8 @@ impl RawVec { Err(_) => capacity_overflow(), } let result = match init { - AllocInit::Uninitialized => alloc.alloc(layout), - AllocInit::Zeroed => alloc.alloc_zeroed(layout), + AllocInit::Uninitialized => alloc.allocate(layout), + AllocInit::Zeroed => alloc.allocate_zeroed(layout), }; let ptr = match result { Ok(ptr) => ptr, @@ -232,7 +232,7 @@ impl RawVec { } /// Returns a shared reference to the allocator backing this `RawVec`. - pub fn alloc_ref(&self) -> &A { + pub fn allocator(&self) -> &A { &self.alloc } @@ -359,7 +359,7 @@ impl RawVec { } } -impl RawVec { +impl RawVec { /// Returns if the buffer needs to grow to fulfill the needed extra capacity. /// Mainly used to make inlining reserve-calls possible without inlining `grow`. fn needs_to_grow(&self, len: usize, additional: usize) -> bool { @@ -471,7 +471,7 @@ fn finish_grow( alloc: &mut A, ) -> Result, TryReserveError> where - A: AllocRef, + A: Allocator, { // Check for the error here to minimize the size of `RawVec::grow_*`. let new_layout = new_layout.map_err(|_| CapacityOverflow)?; @@ -486,17 +486,17 @@ where alloc.grow(ptr, old_layout, new_layout) } } else { - alloc.alloc(new_layout) + alloc.allocate(new_layout) }; memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }) } -unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. fn drop(&mut self) { if let Some((ptr, layout)) = self.current_memory() { - unsafe { self.alloc.dealloc(ptr, layout) } + unsafe { self.alloc.deallocate(ptr, layout) } } } } diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index cb4fe1b46cd75..8c15a24409bab 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -20,13 +20,13 @@ fn allocator_param() { struct BoundedAlloc { fuel: Cell, } - unsafe impl AllocRef for BoundedAlloc { - fn alloc(&self, layout: Layout) -> Result, AllocError> { + unsafe impl Allocator for BoundedAlloc { + fn allocate(&self, layout: Layout) -> Result, AllocError> { let size = layout.size(); if size > self.fuel.get() { return Err(AllocError); } - match Global.alloc(layout) { + match Global.allocate(layout) { ok @ Ok(_) => { self.fuel.set(self.fuel.get() - size); ok @@ -34,8 +34,8 @@ fn allocator_param() { err @ Err(_) => err, } } - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { - unsafe { Global.dealloc(ptr, layout) } + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { Global.deallocate(ptr, layout) } } } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 6dcd0c6056c30..a96be57143d38 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -262,7 +262,7 @@ use core::pin::Pin; use core::ptr::{self, NonNull}; use core::slice::from_raw_parts_mut; -use crate::alloc::{box_free, handle_alloc_error, AllocError, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::string::String; use crate::vec::Vec; @@ -416,7 +416,7 @@ impl Rc { unsafe { Rc::from_ptr(Rc::allocate_for_layout( Layout::new::(), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| mem as *mut RcBox>, )) } @@ -447,7 +447,7 @@ impl Rc { unsafe { Rc::from_ptr(Rc::allocate_for_layout( Layout::new::(), - |layout| Global.alloc_zeroed(layout), + |layout| Global.allocate_zeroed(layout), |mem| mem as *mut RcBox>, )) } @@ -555,7 +555,7 @@ impl Rc<[T]> { unsafe { Rc::from_ptr(Rc::allocate_for_layout( Layout::array::(len).unwrap(), - |layout| Global.alloc_zeroed(layout), + |layout| Global.allocate_zeroed(layout), |mem| { ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[mem::MaybeUninit]> @@ -1040,7 +1040,7 @@ impl Rc { unsafe { Self::allocate_for_layout( Layout::for_value(&*ptr), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox, ) } @@ -1075,7 +1075,7 @@ impl Rc<[T]> { unsafe { Self::allocate_for_layout( Layout::array::(len).unwrap(), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>, ) } @@ -1125,7 +1125,7 @@ impl Rc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem, self.layout); + Global.deallocate(self.mem, self.layout); } } } @@ -1225,7 +1225,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.inner().dec_weak(); if self.inner().weak() == 0 { - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } @@ -2040,7 +2040,7 @@ impl Drop for Weak { // the strong pointers have disappeared. if inner.weak() == 0 { unsafe { - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 949a3bb1d708c..064700fc72c95 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -87,7 +87,7 @@ use core::cmp::Ordering::{self, Less}; use core::mem::{self, size_of}; use core::ptr; -use crate::alloc::{AllocRef, Global}; +use crate::alloc::{Allocator, Global}; use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; @@ -138,7 +138,7 @@ pub use hack::to_vec; // `core::slice::SliceExt` - we need to supply these functions for the // `test_permutations` test mod hack { - use core::alloc::AllocRef; + use core::alloc::Allocator; use crate::boxed::Box; use crate::vec::Vec; @@ -146,33 +146,33 @@ mod hack { // We shouldn't add inline attribute to this since this is used in // `vec!` macro mostly and causes perf regression. See #71204 for // discussion and perf results. - pub fn into_vec(b: Box<[T], A>) -> Vec { + pub fn into_vec(b: Box<[T], A>) -> Vec { unsafe { let len = b.len(); - let (b, alloc) = Box::into_raw_with_alloc(b); + let (b, alloc) = Box::into_raw_with_allocator(b); Vec::from_raw_parts_in(b as *mut T, len, len, alloc) } } #[inline] - pub fn to_vec(s: &[T], alloc: A) -> Vec { + pub fn to_vec(s: &[T], alloc: A) -> Vec { T::to_vec(s, alloc) } pub trait ConvertVec { - fn to_vec(s: &[Self], alloc: A) -> Vec + fn to_vec(s: &[Self], alloc: A) -> Vec where Self: Sized; } impl ConvertVec for T { #[inline] - default fn to_vec(s: &[Self], alloc: A) -> Vec { - struct DropGuard<'a, T, A: AllocRef> { + default fn to_vec(s: &[Self], alloc: A) -> Vec { + struct DropGuard<'a, T, A: Allocator> { vec: &'a mut Vec, num_init: usize, } - impl<'a, T, A: AllocRef> Drop for DropGuard<'a, T, A> { + impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { #[inline] fn drop(&mut self) { // SAFETY: @@ -203,7 +203,7 @@ mod hack { impl ConvertVec for T { #[inline] - fn to_vec(s: &[Self], alloc: A) -> Vec { + fn to_vec(s: &[Self], alloc: A) -> Vec { let mut v = Vec::with_capacity_in(s.len(), alloc); // SAFETY: // allocated above with the capacity of `s`, and initialize to `s.len()` in @@ -464,7 +464,7 @@ impl [T] { /// ``` #[inline] #[unstable(feature = "allocator_api", issue = "32838")] - pub fn to_vec_in(&self, alloc: A) -> Vec + pub fn to_vec_in(&self, alloc: A) -> Vec where T: Clone, { @@ -488,7 +488,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn into_vec(self: Box) -> Vec { + pub fn into_vec(self: Box) -> Vec { // N.B., see the `hack` module in this file for more details. hack::into_vec(self) } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 5ab930a520884..9d478a302e96c 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -22,7 +22,7 @@ use core::slice::from_raw_parts_mut; use core::sync::atomic; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; -use crate::alloc::{box_free, handle_alloc_error, AllocError, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::is_dangling; @@ -434,7 +434,7 @@ impl Arc { unsafe { Arc::from_ptr(Arc::allocate_for_layout( Layout::new::(), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| mem as *mut ArcInner>, )) } @@ -465,7 +465,7 @@ impl Arc { unsafe { Arc::from_ptr(Arc::allocate_for_layout( Layout::new::(), - |layout| Global.alloc_zeroed(layout), + |layout| Global.allocate_zeroed(layout), |mem| mem as *mut ArcInner>, )) } @@ -572,7 +572,7 @@ impl Arc<[T]> { unsafe { Arc::from_ptr(Arc::allocate_for_layout( Layout::array::(len).unwrap(), - |layout| Global.alloc_zeroed(layout), + |layout| Global.allocate_zeroed(layout), |mem| { ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[mem::MaybeUninit]> @@ -1015,7 +1015,7 @@ impl Arc { unsafe { Self::allocate_for_layout( Layout::for_value(&*ptr), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner, ) } @@ -1050,7 +1050,7 @@ impl Arc<[T]> { unsafe { Self::allocate_for_layout( Layout::array::(len).unwrap(), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>, ) } @@ -1102,7 +1102,7 @@ impl Arc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem, self.layout); + Global.deallocate(self.mem, self.layout); } } } @@ -1925,7 +1925,7 @@ impl Drop for Weak { if inner.weak.fetch_sub(1, Release) == 1 { acquire!(inner.weak); - unsafe { Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } + unsafe { Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } } } } diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 5168792092823..9fffb47aa5975 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -68,7 +68,7 @@ use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; -use crate::alloc::{AllocRef, Global}; +use crate::alloc::{Allocator, Global}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::collections::TryReserveError; @@ -298,7 +298,7 @@ use crate::raw_vec::RawVec; /// [`&`]: ../../std/primitive.reference.html #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] -pub struct Vec { +pub struct Vec { buf: RawVec, len: usize, } @@ -433,7 +433,7 @@ impl Vec { } } -impl Vec { +impl Vec { /// Constructs a new, empty `Vec`. /// /// The vector will not allocate until elements are pushed onto it. @@ -555,7 +555,7 @@ impl Vec { /// let p = v.as_mut_ptr(); /// let len = v.len(); /// let cap = v.capacity(); - /// let alloc = v.alloc_ref(); + /// let alloc = v.allocator(); /// /// unsafe { /// // Overwrite memory with 4, 5, 6 @@ -656,7 +656,7 @@ impl Vec { let len = me.len(); let capacity = me.capacity(); let ptr = me.as_mut_ptr(); - let alloc = unsafe { ptr::read(me.alloc_ref()) }; + let alloc = unsafe { ptr::read(me.allocator()) }; (ptr, len, capacity, alloc) } @@ -1058,8 +1058,8 @@ impl Vec { /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn alloc_ref(&self) -> &A { - self.buf.alloc_ref() + pub fn allocator(&self) -> &A { + self.buf.allocator() } /// Forces the length of the vector to `new_len`. @@ -1620,12 +1620,12 @@ impl Vec { // the new vector can take over the original buffer and avoid the copy return mem::replace( self, - Vec::with_capacity_in(self.capacity(), self.alloc_ref().clone()), + Vec::with_capacity_in(self.capacity(), self.allocator().clone()), ); } let other_len = self.len - at; - let mut other = Vec::with_capacity_in(other_len, self.alloc_ref().clone()); + let mut other = Vec::with_capacity_in(other_len, self.allocator().clone()); // Unsafely `set_len` and copy items to `other`. unsafe { @@ -1749,7 +1749,7 @@ impl Vec { } } -impl Vec { +impl Vec { /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. /// /// If `new_len` is greater than `len`, the `Vec` is extended by the @@ -1844,7 +1844,7 @@ impl T> ExtendWith for ExtendFunc { } } -impl Vec { +impl Vec { /// Extend the vector by `n` values, using the given generator. fn extend_with>(&mut self, n: usize, mut value: E) { self.reserve(n); @@ -1904,7 +1904,7 @@ impl Drop for SetLenOnDrop<'_> { } } -impl Vec { +impl Vec { /// Removes consecutive repeated elements in the vector according to the /// [`PartialEq`] trait implementation. /// @@ -1926,7 +1926,7 @@ impl Vec { } } -impl Vec { +impl Vec { /// Removes the first instance of `item` from the vector if the item exists. /// /// This method will be removed soon. @@ -1959,17 +1959,17 @@ pub fn from_elem(elem: T, n: usize) -> Vec { #[doc(hidden)] #[unstable(feature = "allocator_api", issue = "32838")] -pub fn from_elem_in(elem: T, n: usize, alloc: A) -> Vec { +pub fn from_elem_in(elem: T, n: usize, alloc: A) -> Vec { ::from_elem(elem, n, alloc) } // Specialization trait used for Vec::from_elem trait SpecFromElem: Sized { - fn from_elem(elem: Self, n: usize, alloc: A) -> Vec; + fn from_elem(elem: Self, n: usize, alloc: A) -> Vec; } impl SpecFromElem for T { - default fn from_elem(elem: Self, n: usize, alloc: A) -> Vec { + default fn from_elem(elem: Self, n: usize, alloc: A) -> Vec { let mut v = Vec::with_capacity_in(n, alloc); v.extend_with(n, ExtendElement(elem)); v @@ -1978,7 +1978,7 @@ impl SpecFromElem for T { impl SpecFromElem for i8 { #[inline] - fn from_elem(elem: i8, n: usize, alloc: A) -> Vec { + fn from_elem(elem: i8, n: usize, alloc: A) -> Vec { if elem == 0 { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; } @@ -1993,7 +1993,7 @@ impl SpecFromElem for i8 { impl SpecFromElem for u8 { #[inline] - fn from_elem(elem: u8, n: usize, alloc: A) -> Vec { + fn from_elem(elem: u8, n: usize, alloc: A) -> Vec { if elem == 0 { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; } @@ -2008,7 +2008,7 @@ impl SpecFromElem for u8 { impl SpecFromElem for T { #[inline] - fn from_elem(elem: T, n: usize, alloc: A) -> Vec { + fn from_elem(elem: T, n: usize, alloc: A) -> Vec { if elem.is_zero() { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; } @@ -2093,7 +2093,7 @@ unsafe impl IsZero for Option> { //////////////////////////////////////////////////////////////////////////////// #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Deref for Vec { +impl ops::Deref for Vec { type Target = [T]; fn deref(&self) -> &[T] { @@ -2102,17 +2102,17 @@ impl ops::Deref for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::DerefMut for Vec { +impl ops::DerefMut for Vec { fn deref_mut(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } } } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Vec { +impl Clone for Vec { #[cfg(not(test))] fn clone(&self) -> Self { - let alloc = self.alloc_ref().clone(); + let alloc = self.allocator().clone(); <[T]>::to_vec_in(&**self, alloc) } @@ -2122,7 +2122,7 @@ impl Clone for Vec { // NB see the slice::hack module in slice.rs for more information #[cfg(test)] fn clone(&self) -> Self { - let alloc = self.alloc_ref().clone(); + let alloc = self.allocator().clone(); crate::slice::to_vec(&**self, alloc) } @@ -2141,7 +2141,7 @@ impl Clone for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Vec { +impl Hash for Vec { #[inline] fn hash(&self, state: &mut H) { Hash::hash(&**self, state) @@ -2153,7 +2153,7 @@ impl Hash for Vec { message = "vector indices are of type `usize` or ranges of `usize`", label = "vector indices are of type `usize` or ranges of `usize`" )] -impl, A: AllocRef> Index for Vec { +impl, A: Allocator> Index for Vec { type Output = I::Output; #[inline] @@ -2167,7 +2167,7 @@ impl, A: AllocRef> Index for Vec { message = "vector indices are of type `usize` or ranges of `usize`", label = "vector indices are of type `usize` or ranges of `usize`" )] -impl, A: AllocRef> IndexMut for Vec { +impl, A: Allocator> IndexMut for Vec { #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { IndexMut::index_mut(&mut **self, index) @@ -2183,7 +2183,7 @@ impl FromIterator for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for Vec { +impl IntoIterator for Vec { type Item = T; type IntoIter = IntoIter; @@ -2204,7 +2204,7 @@ impl IntoIterator for Vec { fn into_iter(self) -> IntoIter { unsafe { let mut me = ManuallyDrop::new(self); - let alloc = ptr::read(me.alloc_ref()); + let alloc = ptr::read(me.allocator()); let begin = me.as_mut_ptr(); let end = if mem::size_of::() == 0 { arith_offset(begin as *const i8, me.len() as isize) as *const T @@ -2225,7 +2225,7 @@ impl IntoIterator for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, A: AllocRef> IntoIterator for &'a Vec { +impl<'a, T, A: Allocator> IntoIterator for &'a Vec { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; @@ -2235,7 +2235,7 @@ impl<'a, T, A: AllocRef> IntoIterator for &'a Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, A: AllocRef> IntoIterator for &'a mut Vec { +impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; @@ -2245,7 +2245,7 @@ impl<'a, T, A: AllocRef> IntoIterator for &'a mut Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl Extend for Vec { +impl Extend for Vec { #[inline] fn extend>(&mut self, iter: I) { >::spec_extend(self, iter.into_iter()) @@ -2533,7 +2533,7 @@ trait SpecExtend { fn spec_extend(&mut self, iter: I); } -impl SpecExtend for Vec +impl SpecExtend for Vec where I: Iterator, { @@ -2542,7 +2542,7 @@ where } } -impl SpecExtend for Vec +impl SpecExtend for Vec where I: TrustedLen, { @@ -2575,7 +2575,7 @@ where } } -impl SpecExtend> for Vec { +impl SpecExtend> for Vec { fn spec_extend(&mut self, mut iterator: IntoIter) { unsafe { self.append_elements(iterator.as_slice() as _); @@ -2584,7 +2584,7 @@ impl SpecExtend> for Vec { } } -impl<'a, T: 'a, I, A: AllocRef + 'a> SpecExtend<&'a T, I> for Vec +impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec where I: Iterator, T: Clone, @@ -2594,7 +2594,7 @@ where } } -impl<'a, T: 'a, A: AllocRef + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec +impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec where T: Copy, { @@ -2604,7 +2604,7 @@ where } } -impl Vec { +impl Vec { // leaf method to which various SpecFrom/SpecExtend implementations delegate when // they have no further optimizations to apply fn extend_desugared>(&mut self, mut iterator: I) { @@ -2739,7 +2739,7 @@ impl Vec { /// /// [`copy_from_slice`]: ../../std/primitive.slice.html#method.copy_from_slice #[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, T: Copy + 'a, A: AllocRef + 'a> Extend<&'a T> for Vec { +impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec { fn extend>(&mut self, iter: I) { self.spec_extend(iter.into_iter()) } @@ -2771,18 +2771,18 @@ macro_rules! __impl_slice_eq1 { } } -__impl_slice_eq1! { [A: AllocRef] Vec, Vec, #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: AllocRef] Vec, &[U], #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: AllocRef] Vec, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: AllocRef] &[T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } -__impl_slice_eq1! { [A: AllocRef] &mut [T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } -__impl_slice_eq1! { [A: AllocRef] Vec, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } -__impl_slice_eq1! { [A: AllocRef] [T], Vec, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } -__impl_slice_eq1! { [A: AllocRef] Cow<'_, [T]>, Vec where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, Vec, #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, &[U], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] &[T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } +__impl_slice_eq1! { [A: Allocator] &mut [T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } +__impl_slice_eq1! { [A: Allocator] [T], Vec, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } +__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } __impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } __impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: AllocRef, const N: usize] Vec, [U; N], #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: AllocRef, const N: usize] Vec, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator, const N: usize] Vec, [U; N], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator, const N: usize] Vec, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] } // NOTE: some less important impls are omitted to reduce code bloat // FIXME(Centril): Reconsider this? @@ -2796,7 +2796,7 @@ __impl_slice_eq1! { [A: AllocRef, const N: usize] Vec, &[U; N], #[stable(f /// Implements comparison of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Vec { +impl PartialOrd for Vec { #[inline] fn partial_cmp(&self, other: &Self) -> Option { PartialOrd::partial_cmp(&**self, &**other) @@ -2804,11 +2804,11 @@ impl PartialOrd for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Vec {} +impl Eq for Vec {} /// Implements ordering of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Vec { +impl Ord for Vec { #[inline] fn cmp(&self, other: &Self) -> Ordering { Ord::cmp(&**self, &**other) @@ -2816,7 +2816,7 @@ impl Ord for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T, A: AllocRef> Drop for Vec { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec { fn drop(&mut self) { unsafe { // use drop for [T] @@ -2837,35 +2837,35 @@ impl Default for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Vec { +impl fmt::Debug for Vec { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef> for Vec { +impl AsRef> for Vec { fn as_ref(&self) -> &Vec { self } } #[stable(feature = "vec_as_mut", since = "1.5.0")] -impl AsMut> for Vec { +impl AsMut> for Vec { fn as_mut(&mut self) -> &mut Vec { self } } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<[T]> for Vec { +impl AsRef<[T]> for Vec { fn as_ref(&self) -> &[T] { self } } #[stable(feature = "vec_as_mut", since = "1.5.0")] -impl AsMut<[T]> for Vec { +impl AsMut<[T]> for Vec { fn as_mut(&mut self) -> &mut [T] { self } @@ -2920,7 +2920,7 @@ where // note: test pulls in libstd, which causes errors here #[cfg(not(test))] #[stable(feature = "vec_from_box", since = "1.18.0")] -impl From> for Vec { +impl From> for Vec { fn from(s: Box<[T], A>) -> Self { let len = s.len(); Self { buf: RawVec::from_box(s), len } @@ -2930,7 +2930,7 @@ impl From> for Vec { // note: test pulls in libstd, which causes errors here #[cfg(not(test))] #[stable(feature = "box_from_vec", since = "1.20.0")] -impl From> for Box<[T], A> { +impl From> for Box<[T], A> { fn from(v: Vec) -> Self { v.into_boxed_slice() } @@ -2944,7 +2944,7 @@ impl From<&str> for Vec { } #[stable(feature = "array_try_from_vec", since = "1.48.0")] -impl TryFrom> for [T; N] { +impl TryFrom> for [T; N] { type Error = Vec; /// Gets the entire contents of the `Vec` as an array, @@ -3045,8 +3045,10 @@ where /// let iter: std::vec::IntoIter<_> = v.into_iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter -{ +pub struct IntoIter< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { buf: NonNull, phantom: PhantomData, cap: usize, @@ -3056,13 +3058,13 @@ pub struct IntoIter fmt::Debug for IntoIter { +impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("IntoIter").field(&self.as_slice()).finish() } } -impl IntoIter { +impl IntoIter { /// Returns the remaining items of this iterator as a slice. /// /// # Examples @@ -3100,7 +3102,7 @@ impl IntoIter { /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn alloc_ref(&self) -> &A { + pub fn allocator(&self) -> &A { &self.alloc } @@ -3126,19 +3128,19 @@ impl IntoIter { } #[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")] -impl AsRef<[T]> for IntoIter { +impl AsRef<[T]> for IntoIter { fn as_ref(&self) -> &[T] { self.as_slice() } } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for IntoIter {} +unsafe impl Send for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for IntoIter {} +unsafe impl Sync for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = T; #[inline] @@ -3195,7 +3197,7 @@ impl Iterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { +impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { if self.end == self.ptr { @@ -3215,23 +3217,23 @@ impl DoubleEndedIterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { fn is_empty(&self) -> bool { self.ptr == self.end } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for IntoIter {} +unsafe impl TrustedLen for IntoIter {} #[doc(hidden)] #[unstable(issue = "none", feature = "std_internals")] // T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr // and thus we can't implement drop-handling -unsafe impl TrustedRandomAccess for IntoIter +unsafe impl TrustedRandomAccess for IntoIter where T: Copy, { @@ -3241,7 +3243,7 @@ where } #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] -impl Clone for IntoIter { +impl Clone for IntoIter { #[cfg(not(test))] fn clone(&self) -> Self { self.as_slice().to_vec_in(self.alloc.clone()).into_iter() @@ -3253,11 +3255,11 @@ impl Clone for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T, A: AllocRef> Drop for IntoIter { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter { fn drop(&mut self) { - struct DropGuard<'a, T, A: AllocRef>(&'a mut IntoIter); + struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter); - impl Drop for DropGuard<'_, T, A> { + impl Drop for DropGuard<'_, T, A> { fn drop(&mut self) { unsafe { // `IntoIter::alloc` is not used anymore after this @@ -3278,10 +3280,10 @@ unsafe impl<#[may_dangle] T, A: AllocRef> Drop for IntoIter { } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for IntoIter {} +unsafe impl InPlaceIterable for IntoIter {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for IntoIter { +unsafe impl SourceIter for IntoIter { type Source = Self; #[inline] @@ -3320,7 +3322,7 @@ impl AsIntoIter for IntoIter { pub struct Drain< 'a, T: 'a, - #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef + 'a = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, > { /// Index of tail to preserve tail_start: usize, @@ -3332,13 +3334,13 @@ pub struct Drain< } #[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for Drain<'_, T, A> { +impl fmt::Debug for Drain<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() } } -impl<'a, T, A: AllocRef> Drain<'a, T, A> { +impl<'a, T, A: Allocator> Drain<'a, T, A> { /// Returns the remaining items of this iterator as a slice. /// /// # Examples @@ -3358,25 +3360,25 @@ impl<'a, T, A: AllocRef> Drain<'a, T, A> { /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn alloc_ref(&self) -> &A { - unsafe { self.vec.as_ref().alloc_ref() } + pub fn allocator(&self) -> &A { + unsafe { self.vec.as_ref().allocator() } } } #[stable(feature = "vec_drain_as_slice", since = "1.46.0")] -impl<'a, T, A: AllocRef> AsRef<[T]> for Drain<'a, T, A> { +impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> { fn as_ref(&self) -> &[T] { self.as_slice() } } #[stable(feature = "drain", since = "1.6.0")] -unsafe impl Sync for Drain<'_, T, A> {} +unsafe impl Sync for Drain<'_, T, A> {} #[stable(feature = "drain", since = "1.6.0")] -unsafe impl Send for Drain<'_, T, A> {} +unsafe impl Send for Drain<'_, T, A> {} #[stable(feature = "drain", since = "1.6.0")] -impl Iterator for Drain<'_, T, A> { +impl Iterator for Drain<'_, T, A> { type Item = T; #[inline] @@ -3390,7 +3392,7 @@ impl Iterator for Drain<'_, T, A> { } #[stable(feature = "drain", since = "1.6.0")] -impl DoubleEndedIterator for Drain<'_, T, A> { +impl DoubleEndedIterator for Drain<'_, T, A> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) }) @@ -3398,13 +3400,13 @@ impl DoubleEndedIterator for Drain<'_, T, A> { } #[stable(feature = "drain", since = "1.6.0")] -impl Drop for Drain<'_, T, A> { +impl Drop for Drain<'_, T, A> { fn drop(&mut self) { /// Continues dropping the remaining elements in the `Drain`, then moves back the /// un-`Drain`ed elements to restore the original `Vec`. - struct DropGuard<'r, 'a, T, A: AllocRef>(&'r mut Drain<'a, T, A>); + struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>); - impl<'r, 'a, T, A: AllocRef> Drop for DropGuard<'r, 'a, T, A> { + impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> { fn drop(&mut self) { // Continue the same loop we have below. If the loop already finished, this does // nothing. @@ -3440,17 +3442,17 @@ impl Drop for Drain<'_, T, A> { } #[stable(feature = "drain", since = "1.6.0")] -impl ExactSizeIterator for Drain<'_, T, A> { +impl ExactSizeIterator for Drain<'_, T, A> { fn is_empty(&self) -> bool { self.iter.is_empty() } } #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Drain<'_, T, A> {} +unsafe impl TrustedLen for Drain<'_, T, A> {} #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Drain<'_, T, A> {} +impl FusedIterator for Drain<'_, T, A> {} /// A splicing iterator for `Vec`. /// @@ -3469,14 +3471,14 @@ impl FusedIterator for Drain<'_, T, A> {} pub struct Splice< 'a, I: Iterator + 'a, - #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef + 'a = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, > { drain: Drain<'a, I::Item, A>, replace_with: I, } #[stable(feature = "vec_splice", since = "1.21.0")] -impl Iterator for Splice<'_, I, A> { +impl Iterator for Splice<'_, I, A> { type Item = I::Item; fn next(&mut self) -> Option { @@ -3489,17 +3491,17 @@ impl Iterator for Splice<'_, I, A> { } #[stable(feature = "vec_splice", since = "1.21.0")] -impl DoubleEndedIterator for Splice<'_, I, A> { +impl DoubleEndedIterator for Splice<'_, I, A> { fn next_back(&mut self) -> Option { self.drain.next_back() } } #[stable(feature = "vec_splice", since = "1.21.0")] -impl ExactSizeIterator for Splice<'_, I, A> {} +impl ExactSizeIterator for Splice<'_, I, A> {} #[stable(feature = "vec_splice", since = "1.21.0")] -impl Drop for Splice<'_, I, A> { +impl Drop for Splice<'_, I, A> { fn drop(&mut self) { self.drain.by_ref().for_each(drop); @@ -3540,7 +3542,7 @@ impl Drop for Splice<'_, I, A> { } /// Private helper methods for `Splice::drop` -impl Drain<'_, T, A> { +impl Drain<'_, T, A> { /// The range from `self.vec.len` to `self.tail_start` contains elements /// that have been moved out. /// Fill that range as much as possible with new elements from the `replace_with` iterator. @@ -3599,7 +3601,7 @@ pub struct DrainFilter< 'a, T, F, - #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > where F: FnMut(&mut T) -> bool, { @@ -3620,20 +3622,20 @@ pub struct DrainFilter< panic_flag: bool, } -impl DrainFilter<'_, T, F, A> +impl DrainFilter<'_, T, F, A> where F: FnMut(&mut T) -> bool, { /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn alloc_ref(&self) -> &A { - self.vec.alloc_ref() + pub fn allocator(&self) -> &A { + self.vec.allocator() } } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Iterator for DrainFilter<'_, T, F, A> +impl Iterator for DrainFilter<'_, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -3671,19 +3673,19 @@ where } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Drop for DrainFilter<'_, T, F, A> +impl Drop for DrainFilter<'_, T, F, A> where F: FnMut(&mut T) -> bool, { fn drop(&mut self) { - struct BackshiftOnDrop<'a, 'b, T, F, A: AllocRef> + struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator> where F: FnMut(&mut T) -> bool, { drain: &'b mut DrainFilter<'a, T, F, A>, } - impl<'a, 'b, T, F, A: AllocRef> Drop for BackshiftOnDrop<'a, 'b, T, F, A> + impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A> where F: FnMut(&mut T) -> bool, { diff --git a/library/alloc/tests/heap.rs b/library/alloc/tests/heap.rs index a7239a4b14fae..246b341eeb387 100644 --- a/library/alloc/tests/heap.rs +++ b/library/alloc/tests/heap.rs @@ -1,4 +1,4 @@ -use std::alloc::{AllocRef, Global, Layout, System}; +use std::alloc::{Allocator, Global, Layout, System}; /// Issue #45955 and #62251. #[test] @@ -11,7 +11,7 @@ fn std_heap_overaligned_request() { check_overalign_requests(Global) } -fn check_overalign_requests(allocator: T) { +fn check_overalign_requests(allocator: T) { for &align in &[4, 8, 16, 32] { // less than and bigger than `MIN_ALIGN` for &size in &[align / 2, align - 1] { @@ -20,7 +20,7 @@ fn check_overalign_requests(allocator: T) { unsafe { let pointers: Vec<_> = (0..iterations) .map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() + allocator.allocate(Layout::from_size_align(size, align).unwrap()).unwrap() }) .collect(); for &ptr in &pointers { @@ -33,7 +33,7 @@ fn check_overalign_requests(allocator: T) { // Clean up for &ptr in &pointers { - allocator.dealloc( + allocator.deallocate( ptr.as_non_null_ptr(), Layout::from_size_align(size, align).unwrap(), ) diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index b13019146568c..604835e6cc4a6 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1978,9 +1978,14 @@ fn const_str_ptr() { const B: &'static [u8; 2] = &A; const C: *const u8 = B as *const u8; - unsafe { + // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131) + #[cfg(not(miri))] + { let foo = &A as *const u8; assert_eq!(foo, C); + } + + unsafe { assert_eq!(from_utf8_unchecked(&A), "hi"); assert_eq!(*C, A[0]); assert_eq!(*(&B[0] as *const u8), A[0]); diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 339d85902b83f..57c6624b64f9e 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -19,7 +19,7 @@ const fn size_align() -> (usize, usize) { /// even though `GlobalAlloc` requires that all memory requests /// be non-zero in size. A caller must either ensure that conditions /// like this are met, use specific allocators with looser -/// requirements, or use the more lenient `AllocRef` interface.) +/// requirements, or use the more lenient `Allocator` interface.) #[stable(feature = "alloc_layout", since = "1.28.0")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[lang = "alloc_layout"] diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index bc874e2e52242..045eb58d0135a 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -40,14 +40,14 @@ impl fmt::Display for AllocError { } } -/// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of +/// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of /// data described via [`Layout`][]. /// -/// `AllocRef` is designed to be implemented on ZSTs, references, or smart pointers because having +/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers because having /// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the /// allocated memory. /// -/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `AllocRef`. If an underlying +/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `Allocator`. If an underlying /// allocator does not support this (like jemalloc) or return a null pointer (such as /// `libc::malloc`), this must be caught by the implementation. /// @@ -56,18 +56,18 @@ impl fmt::Display for AllocError { /// Some of the methods require that a memory block be *currently allocated* via an allocator. This /// means that: /// -/// * the starting address for that memory block was previously returned by [`alloc`], [`grow`], or +/// * the starting address for that memory block was previously returned by [`allocate`], [`grow`], or /// [`shrink`], and /// /// * the memory block has not been subsequently deallocated, where blocks are either deallocated -/// directly by being passed to [`dealloc`] or were changed by being passed to [`grow`] or +/// directly by being passed to [`deallocate`] or were changed by being passed to [`grow`] or /// [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer /// remains valid. /// -/// [`alloc`]: AllocRef::alloc -/// [`grow`]: AllocRef::grow -/// [`shrink`]: AllocRef::shrink -/// [`dealloc`]: AllocRef::dealloc +/// [`allocate`]: Allocator::allocate +/// [`grow`]: Allocator::grow +/// [`shrink`]: Allocator::shrink +/// [`deallocate`]: Allocator::deallocate /// /// ### Memory fitting /// @@ -79,7 +79,7 @@ impl fmt::Display for AllocError { /// /// * The provided [`layout.size()`] must fall in the range `min ..= max`, where: /// - `min` is the size of the layout most recently used to allocate the block, and -/// - `max` is the latest actual size returned from [`alloc`], [`grow`], or [`shrink`]. +/// - `max` is the latest actual size returned from [`allocate`], [`grow`], or [`shrink`]. /// /// [`layout.align()`]: Layout::align /// [`layout.size()`]: Layout::size @@ -97,7 +97,7 @@ impl fmt::Display for AllocError { /// /// [*currently allocated*]: #currently-allocated-memory #[unstable(feature = "allocator_api", issue = "32838")] -pub unsafe trait AllocRef { +pub unsafe trait Allocator { /// Attempts to allocate a block of memory. /// /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`. @@ -118,9 +118,9 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc(&self, layout: Layout) -> Result, AllocError>; + fn allocate(&self, layout: Layout) -> Result, AllocError>; - /// Behaves like `alloc`, but also ensures that the returned memory is zero-initialized. + /// Behaves like `allocate`, but also ensures that the returned memory is zero-initialized. /// /// # Errors /// @@ -135,8 +135,8 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { - let ptr = self.alloc(layout)?; + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + let ptr = self.allocate(layout)?; // SAFETY: `alloc` returns a valid memory block unsafe { ptr.as_non_null_ptr().as_ptr().write_bytes(0, ptr.len()) } Ok(ptr) @@ -151,7 +151,7 @@ pub unsafe trait AllocRef { /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout); + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout); /// Attempts to extend the memory block. /// @@ -200,7 +200,7 @@ pub unsafe trait AllocRef { "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - let new_ptr = self.alloc(new_layout)?; + let new_ptr = self.allocate(new_layout)?; // SAFETY: because `new_layout.size()` must be greater than or equal to // `old_layout.size()`, both the old and new memory allocation are valid for reads and @@ -209,7 +209,7 @@ pub unsafe trait AllocRef { // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size()); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); } Ok(new_ptr) @@ -261,7 +261,7 @@ pub unsafe trait AllocRef { "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - let new_ptr = self.alloc_zeroed(new_layout)?; + let new_ptr = self.allocate_zeroed(new_layout)?; // SAFETY: because `new_layout.size()` must be greater than or equal to // `old_layout.size()`, both the old and new memory allocation are valid for reads and @@ -270,7 +270,7 @@ pub unsafe trait AllocRef { // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size()); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); } Ok(new_ptr) @@ -323,7 +323,7 @@ pub unsafe trait AllocRef { "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" ); - let new_ptr = self.alloc(new_layout)?; + let new_ptr = self.allocate(new_layout)?; // SAFETY: because `new_layout.size()` must be lower than or equal to // `old_layout.size()`, both the old and new memory allocation are valid for reads and @@ -332,15 +332,15 @@ pub unsafe trait AllocRef { // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_layout.size()); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); } Ok(new_ptr) } - /// Creates a "by reference" adaptor for this instance of `AllocRef`. + /// Creates a "by reference" adaptor for this instance of `Allocator`. /// - /// The returned adaptor also implements `AllocRef` and will simply borrow this. + /// The returned adaptor also implements `Allocator` and will simply borrow this. #[inline(always)] fn by_ref(&self) -> &Self { self @@ -348,24 +348,24 @@ pub unsafe trait AllocRef { } #[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl AllocRef for &A +unsafe impl Allocator for &A where - A: AllocRef + ?Sized, + A: Allocator + ?Sized, { #[inline] - fn alloc(&self, layout: Layout) -> Result, AllocError> { - (**self).alloc(layout) + fn allocate(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate(layout) } #[inline] - fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { - (**self).alloc_zeroed(layout) + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate_zeroed(layout) } #[inline] - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).dealloc(ptr, layout) } + unsafe { (**self).deallocate(ptr, layout) } } #[inline] diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 4ed62a620c4df..0c65c1c9eb7e9 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -403,7 +403,7 @@ impl<'a> Arguments<'a> { /// ```rust /// #![feature(fmt_as_str)] /// - /// use core::fmt::Arguments; + /// use std::fmt::Arguments; /// /// fn write_str(_: &str) { /* ... */ } /// diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs index ab162638a1cfe..560dd25ecff42 100644 --- a/library/core/src/future/pending.rs +++ b/library/core/src/future/pending.rs @@ -21,7 +21,7 @@ pub struct Pending { /// # Examples /// /// ```no_run -/// use core::future; +/// use std::future; /// /// # async fn run() { /// let future = future::pending(); diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index af63e1bb097b8..9ae118e29f110 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -3,7 +3,7 @@ use crate::future::Future; use crate::pin::Pin; use crate::task::{Context, Poll}; -/// Creates a future that wraps a function returning `Poll`. +/// Creates a future that wraps a function returning [`Poll`]. /// /// Polling the future delegates to the wrapped function. /// @@ -13,7 +13,7 @@ use crate::task::{Context, Poll}; /// #![feature(future_poll_fn)] /// # async fn run() { /// use core::future::poll_fn; -/// use core::task::{Context, Poll}; +/// use std::task::{Context, Poll}; /// /// fn read_line(_cx: &mut Context<'_>) -> Poll { /// Poll::Ready("Hello, World!".into()) @@ -31,7 +31,7 @@ where PollFn { f } } -/// A Future that wraps a function returning `Poll`. +/// A Future that wraps a function returning [`Poll`]. /// /// This `struct` is created by [`poll_fn()`]. See its /// documentation for more. diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs index e98f5c570bf3c..b0c7fbb1d7a76 100644 --- a/library/core/src/future/ready.rs +++ b/library/core/src/future/ready.rs @@ -33,7 +33,7 @@ impl Future for Ready { /// # Examples /// /// ``` -/// use core::future; +/// use std::future; /// /// # async fn run() { /// let a = future::ready(1); diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 1a588b314c4f1..73df8e53f82a4 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1732,6 +1732,11 @@ extern "rust-intrinsic" { /// See documentation of `<*const T>::guaranteed_ne` for details. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] pub fn ptr_guaranteed_ne(ptr: *const T, other: *const T) -> bool; + + /// Allocate at compile time. Should not be called at runtime. + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + #[cfg(not(bootstrap))] + pub fn const_allocate(size: usize, align: usize) -> *mut u8; } // Some functions are defined here because they accidentally got made diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e3b004be39afb..bb76683e0fef4 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -68,6 +68,7 @@ #![feature(arbitrary_self_types)] #![feature(asm)] #![feature(cfg_target_has_atomic)] +#![cfg_attr(not(bootstrap), feature(const_heap))] #![feature(const_alloc_layout)] #![feature(const_discriminant)] #![feature(const_cell_into_inner)] diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 34a974b827158..03bb849509ad4 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -189,7 +189,7 @@ impl<'a> Location<'a> { /// # Examples /// /// ``` - /// use core::panic::Location; + /// use std::panic::Location; /// /// /// Returns the [`Location`] at which it is called. /// #[track_caller] diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 5dc7171a7dc26..d849008b88030 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -439,11 +439,11 @@ impl NonNull<[T]> { /// ```rust /// #![feature(allocator_api, ptr_as_uninit)] /// - /// use std::alloc::{AllocRef, Layout, Global}; + /// use std::alloc::{Allocator, Layout, Global}; /// use std::mem::MaybeUninit; /// use std::ptr::NonNull; /// - /// let memory: NonNull<[u8]> = Global.alloc(Layout::new::<[u8; 32]>())?; + /// let memory: NonNull<[u8]> = Global.allocate(Layout::new::<[u8; 32]>())?; /// // This is safe as `memory` is valid for reads and writes for `memory.len()` many bytes. /// // Note that calling `memory.as_mut()` is not allowed here as the content may be uninitialized. /// # #[allow(unused_variables)] diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index e221aaf3fd6d6..cbf6990001589 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -1,15 +1,18 @@ -/// Extracts the successful type of a `Poll`. +/// Extracts the successful type of a [`Poll`]. /// -/// This macro bakes in propagation of `Pending` signals by returning early. +/// This macro bakes in propagation of [`Pending`] signals by returning early. +/// +/// [`Poll`]: crate::task::Poll +/// [`Pending`]: crate::task::Poll::Pending /// /// # Examples /// /// ``` /// #![feature(ready_macro)] /// -/// use core::task::{ready, Context, Poll}; -/// use core::future::{self, Future}; -/// use core::pin::Pin; +/// use std::task::{ready, Context, Poll}; +/// use std::future::{self, Future}; +/// use std::pin::Pin; /// /// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { /// let mut fut = future::ready(42); @@ -28,9 +31,9 @@ /// ``` /// # #![feature(ready_macro)] /// # -/// # use core::task::{Context, Poll}; -/// # use core::future::{self, Future}; -/// # use core::pin::Pin; +/// # use std::task::{Context, Poll}; +/// # use std::future::{self, Future}; +/// # use std::pin::Pin; /// # /// # pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { /// # let mut fut = future::ready(42); diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 375b015ccc8df..819d57a934dc4 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -149,7 +149,7 @@ impl System { } } - // SAFETY: Same as `AllocRef::grow` + // SAFETY: Same as `Allocator::grow` #[inline] unsafe fn grow_impl( &self, @@ -190,29 +190,29 @@ impl System { old_size => unsafe { let new_ptr = self.alloc_impl(new_layout, zeroed)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); - AllocRef::dealloc(&self, ptr, old_layout); + Allocator::deallocate(&self, ptr, old_layout); Ok(new_ptr) }, } } } -// The AllocRef impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl, +// The Allocator impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl, // which is in `std::sys::*::alloc`. #[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl AllocRef for System { +unsafe impl Allocator for System { #[inline] - fn alloc(&self, layout: Layout) -> Result, AllocError> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, false) } #[inline] - fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, true) } #[inline] - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller @@ -257,7 +257,7 @@ unsafe impl AllocRef for System { match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - AllocRef::dealloc(&self, ptr, old_layout); + Allocator::deallocate(&self, ptr, old_layout); Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, @@ -277,9 +277,9 @@ unsafe impl AllocRef for System { // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // for `dealloc` must be upheld by the caller. new_size => unsafe { - let new_ptr = AllocRef::alloc(&self, new_layout)?; + let new_ptr = Allocator::allocate(&self, new_layout)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); - AllocRef::dealloc(&self, ptr, old_layout); + Allocator::deallocate(&self, ptr, old_layout); Ok(new_ptr) }, } diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs index f9caeaf98e2fb..65497817f8160 100644 --- a/library/std/src/io/buffered/mod.rs +++ b/library/std/src/io/buffered/mod.rs @@ -126,6 +126,51 @@ impl IntoInnerError { pub fn into_inner(self) -> W { self.0 } + + /// Consumes the [`IntoInnerError`] and returns the error which caused the call to + /// [`BufWriter::into_inner()`] to fail. Unlike `error`, this can be used to + /// obtain ownership of the underlying error. + /// + /// # Example + /// ``` + /// #![feature(io_into_inner_error_parts)] + /// use std::io::{BufWriter, ErrorKind, Write}; + /// + /// let mut not_enough_space = [0u8; 10]; + /// let mut stream = BufWriter::new(not_enough_space.as_mut()); + /// write!(stream, "this cannot be actually written").unwrap(); + /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small"); + /// let err = into_inner_err.into_error(); + /// assert_eq!(err.kind(), ErrorKind::WriteZero); + /// ``` + #[unstable(feature = "io_into_inner_error_parts", issue = "79704")] + pub fn into_error(self) -> Error { + self.1 + } + + /// Consumes the [`IntoInnerError`] and returns the error which caused the call to + /// [`BufWriter::into_inner()`] to fail, and the underlying writer. + /// + /// This can be used to simply obtain ownership of the underlying error; it can also be used for + /// advanced error recovery. + /// + /// # Example + /// ``` + /// #![feature(io_into_inner_error_parts)] + /// use std::io::{BufWriter, ErrorKind, Write}; + /// + /// let mut not_enough_space = [0u8; 10]; + /// let mut stream = BufWriter::new(not_enough_space.as_mut()); + /// write!(stream, "this cannot be actually written").unwrap(); + /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small"); + /// let (err, recovered_writer) = into_inner_err.into_parts(); + /// assert_eq!(err.kind(), ErrorKind::WriteZero); + /// assert_eq!(recovered_writer.buffer(), b"t be actually written"); + /// ``` + #[unstable(feature = "io_into_inner_error_parts", issue = "79704")] + pub fn into_parts(self) -> (Error, W) { + (self.1, self.0) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 6b3c86cb0df87..00bf8b9af7384 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -306,6 +306,10 @@ impl BufRead for &[u8] { /// /// Note that writing updates the slice to point to the yet unwritten part. /// The slice will be empty when it has been completely overwritten. +/// +/// If the number of bytes to be written exceeds the size of the slice, write operations will +/// return short writes: ultimately, `Ok(0)`; in this situation, `write_all` returns an error of +/// kind `ErrorKind::WriteZero`. #[stable(feature = "rust1", since = "1.0.0")] impl Write for &mut [u8] { #[inline] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f33804c988a1a..6c240cb4c3ed9 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -212,6 +212,7 @@ all(target_vendor = "fortanix", target_env = "sgx"), feature(slice_index_methods, coerce_unsized, sgx_platform) )] +#![deny(rustc::existing_doc_keyword)] #![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array))] // std is implemented with unstable features, many of which are internal // compiler details that will never be stable @@ -301,6 +302,7 @@ #![feature(rustc_private)] #![feature(shrink_to)] #![feature(slice_concat_ext)] +#![feature(slice_fill)] #![feature(slice_internals)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 83a282c8cd6b5..55171ef2292d7 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -198,7 +198,7 @@ mod prim_bool {} /// words, they can't return `!` from every code path. As an example, this code doesn't compile: /// /// ```compile_fail -/// use core::ops::Add; +/// use std::ops::Add; /// /// fn foo() -> impl Add { /// unimplemented!() @@ -208,7 +208,7 @@ mod prim_bool {} /// But this code does: /// /// ``` -/// use core::ops::Add; +/// use std::ops::Add; /// /// fn foo() -> impl Add { /// if true { diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs deleted file mode 100644 index 3d2366554b5b2..0000000000000 --- a/library/std/src/sys/unix/ext/net.rs +++ /dev/null @@ -1,1768 +0,0 @@ -//! Unix-specific networking functionality. - -#![stable(feature = "unix_socket", since = "1.10.0")] - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests; - -// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? -#[cfg(not(unix))] -#[allow(non_camel_case_types)] -mod libc { - pub use libc::c_int; - pub type socklen_t = u32; - pub struct sockaddr; - #[derive(Clone)] - pub struct sockaddr_un; -} - -use crate::ascii; -use crate::ffi::OsStr; -use crate::fmt; -use crate::io::{self, Initializer, IoSlice, IoSliceMut}; -use crate::mem; -use crate::net::{self, Shutdown}; -use crate::os::unix::ffi::OsStrExt; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use crate::path::Path; -use crate::sys::net::Socket; -use crate::sys::{self, cvt}; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; -use crate::time::Duration; - -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -use crate::os::unix::ucred; - -#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -pub use ucred::UCred; - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" -))] -use libc::MSG_NOSIGNAL; -#[cfg(not(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" -)))] -const MSG_NOSIGNAL: libc::c_int = 0x0; - -fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { - // Work with an actual instance of the type since using a null pointer is UB - let base = addr as *const _ as usize; - let path = &addr.sun_path as *const _ as usize; - path - base -} - -unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { - let mut addr: libc::sockaddr_un = mem::zeroed(); - addr.sun_family = libc::AF_UNIX as libc::sa_family_t; - - let bytes = path.as_os_str().as_bytes(); - - if bytes.contains(&0) { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "paths may not contain interior null bytes", - )); - } - - if bytes.len() >= addr.sun_path.len() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "path must be shorter than SUN_LEN", - )); - } - for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { - *dst = *src as libc::c_char; - } - // null byte for pathname addresses is already there because we zeroed the - // struct - - let mut len = sun_path_offset(&addr) + bytes.len(); - match bytes.get(0) { - Some(&0) | None => {} - Some(_) => len += 1, - } - Ok((addr, len as libc::socklen_t)) -} - -enum AddressKind<'a> { - Unnamed, - Pathname(&'a Path), - Abstract(&'a [u8]), -} - -/// An address associated with a Unix socket. -/// -/// # Examples -/// -/// ``` -/// use std::os::unix::net::UnixListener; -/// -/// let socket = match UnixListener::bind("/tmp/sock") { -/// Ok(sock) => sock, -/// Err(e) => { -/// println!("Couldn't bind: {:?}", e); -/// return -/// } -/// }; -/// let addr = socket.local_addr().expect("Couldn't get local address"); -/// ``` -#[derive(Clone)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct SocketAddr { - addr: libc::sockaddr_un, - len: libc::socklen_t, -} - -impl SocketAddr { - fn new(f: F) -> io::Result - where - F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, - { - unsafe { - let mut addr: libc::sockaddr_un = mem::zeroed(); - let mut len = mem::size_of::() as libc::socklen_t; - cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; - SocketAddr::from_parts(addr, len) - } - } - - fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { - if len == 0 { - // When there is a datagram from unnamed unix socket - // linux returns zero bytes of address - len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address - } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "file descriptor did not correspond to a Unix socket", - )); - } - - Ok(SocketAddr { addr, len }) - } - - /// Returns `true` if the address is unnamed. - /// - /// # Examples - /// - /// A named address: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), false); - /// Ok(()) - /// } - /// ``` - /// - /// An unnamed address: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), true); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn is_unnamed(&self) -> bool { - if let AddressKind::Unnamed = self.address() { true } else { false } - } - - /// Returns the contents of this address if it is a `pathname` address. - /// - /// # Examples - /// - /// With a pathname: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// use std::path::Path; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); - /// Ok(()) - /// } - /// ``` - /// - /// Without a pathname: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), None); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn as_pathname(&self) -> Option<&Path> { - if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } - } - - fn address(&self) -> AddressKind<'_> { - let len = self.len as usize - sun_path_offset(&self.addr); - let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; - - // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses - if len == 0 - || (cfg!(not(any(target_os = "linux", target_os = "android"))) - && self.addr.sun_path[0] == 0) - { - AddressKind::Unnamed - } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(&path[1..len]) - } else { - AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) - } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.address() { - AddressKind::Unnamed => write!(fmt, "(unnamed)"), - AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), - AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), - } - } -} - -struct AsciiEscaped<'a>(&'a [u8]); - -impl<'a> fmt::Display for AsciiEscaped<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "\"")?; - for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { - write!(fmt, "{}", byte as char)?; - } - write!(fmt, "\"") - } -} - -/// A Unix stream socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixStream; -/// use std::io::prelude::*; -/// -/// fn main() -> std::io::Result<()> { -/// let mut stream = UnixStream::connect("/path/to/my/socket")?; -/// stream.write_all(b"hello world")?; -/// let mut response = String::new(); -/// stream.read_to_string(&mut response)?; -/// println!("{}", response); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixStream(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixStream"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixStream { - /// Connects to the socket named by `path`. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = match UnixStream::connect("/tmp/sock") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; - Ok(UnixStream(inner)) - } - } - inner(path.as_ref()) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixStream`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let (sock1, sock2) = match UnixStream::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't create a pair of sockets: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; - Ok((UnixStream(i1), UnixStream(i2))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixStream` is a reference to the same stream that this - /// object references. Both handles will read and write the same stream of - /// data, and options set on one stream will be propagated to the other - /// stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixStream) - } - - /// Returns the socket address of the local half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the socket address of the remote half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) - } - - /// Gets the peer credentials for this Unix domain socket. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(peer_credentials_unix_socket)] - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" - ))] - pub fn peer_cred(&self) -> io::Result { - ucred::peer_cred(self) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`read`]: io::Read::read - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// [`read`]: io::Read::read - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UdpSocket::bind("127.0.0.1:34254")?; - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); - /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// if let Ok(Some(err)) = socket.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns `None`. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shuts down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::net::Shutdown; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } - - /// Receives data on the socket from the remote address to which it is - /// connected, without removing that data from the queue. On success, - /// returns the number of bytes peeked. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recv` system call. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.0.peek(buf) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Read for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - io::Read::read(&mut &*self, buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - io::Read::read_vectored(&mut &*self, bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - io::Read::is_read_vectored(&&*self) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Read for &'a UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Write for UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - io::Write::write(&mut &*self, buf) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - io::Write::write_vectored(&mut &*self, bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - io::Write::is_write_vectored(&&*self) - } - - fn flush(&mut self) -> io::Result<()> { - io::Write::flush(&mut &*self) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Write for &'a UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixStream { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixStream { - unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixStream { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpStream { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpListener { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::UdpSocket { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} - -/// A structure representing a Unix domain socket server. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// fn main() -> std::io::Result<()> { -/// let listener = UnixListener::bind("/path/to/the/socket")?; -/// -/// // accept connections and process them, spawning a new thread for each one -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// /* connection succeeded */ -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// /* connection failed */ -/// break; -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixListener(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixListener"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - builder.finish() - } -} - -impl UnixListener { - /// Creates a new `UnixListener` bound to the specified socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = match UnixListener::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(*inner.as_inner(), 128))?; - - Ok(UnixListener(inner)) - } - } - inner(path.as_ref()) - } - - /// Accepts a new incoming connection to this listener. - /// - /// This function will block the calling thread until a new Unix connection - /// is established. When established, the corresponding [`UnixStream`] and - /// the remote peer's address will be returned. - /// - /// [`UnixStream`]: crate::os::unix::net::UnixStream - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// - /// match listener.accept() { - /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), - /// Err(e) => println!("accept function failed: {:?}", e), - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; - let mut len = mem::size_of_val(&storage) as libc::socklen_t; - let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; - let addr = SocketAddr::from_parts(storage, len)?; - Ok((UnixStream(sock), addr)) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixListener` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one listener will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let listener_copy = listener.try_clone().expect("try_clone failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixListener) - } - - /// Returns the local socket address of this listener. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let addr = listener.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// This will result in the `accept` operation becoming nonblocking, - /// i.e., immediately returning from their calls. If the IO operation is - /// successful, `Ok` is returned and no further action is required. If the - /// IO operation could not be completed and needs to be retried, an error - /// with kind [`io::ErrorKind::WouldBlock`] is returned. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/tmp/sock")?; - /// - /// if let Ok(Some(err)) = listener.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns `None`. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Returns an iterator over incoming connections. - /// - /// The iterator will never return [`None`] and will also not yield the - /// peer's [`SocketAddr`] structure. - /// - /// # Examples - /// - /// ```no_run - /// use std::thread; - /// use std::os::unix::net::{UnixStream, UnixListener}; - /// - /// fn handle_client(stream: UnixStream) { - /// // ... - /// } - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// - /// for stream in listener.incoming() { - /// match stream { - /// Ok(stream) => { - /// thread::spawn(|| handle_client(stream)); - /// } - /// Err(err) => { - /// break; - /// } - /// } - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn incoming(&self) -> Incoming<'_> { - Incoming { listener: self } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixListener { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixListener { - unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixListener { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> IntoIterator for &'a UnixListener { - type Item = io::Result; - type IntoIter = Incoming<'a>; - - fn into_iter(self) -> Incoming<'a> { - self.incoming() - } -} - -/// An iterator over incoming connections to a [`UnixListener`]. -/// -/// It will never return [`None`]. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// fn main() -> std::io::Result<()> { -/// let listener = UnixListener::bind("/path/to/the/socket")?; -/// -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// break; -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -#[derive(Debug)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct Incoming<'a> { - listener: &'a UnixListener, -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> Iterator for Incoming<'a> { - type Item = io::Result; - - fn next(&mut self) -> Option> { - Some(self.listener.accept().map(|s| s.0)) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::MAX, None) - } -} - -/// A Unix datagram socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixDatagram; -/// -/// fn main() -> std::io::Result<()> { -/// let socket = UnixDatagram::bind("/path/to/my/socket")?; -/// socket.send_to(b"hello world", "/path/to/other/socket")?; -/// let mut buf = [0; 100]; -/// let (count, address) = socket.recv_from(&mut buf)?; -/// println!("socket {:?} sent {:?}", address, &buf[..count]); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixDatagram(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixDatagram { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixDatagram"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixDatagram { - /// Creates a Unix datagram socket bound to the given path. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = match UnixDatagram::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't bind: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let socket = UnixDatagram::unbound()?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; - - Ok(socket) - } - } - inner(path.as_ref()) - } - - /// Creates a Unix Datagram socket which is not bound to any address. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = match UnixDatagram::unbound() { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn unbound() -> io::Result { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; - Ok(UnixDatagram(inner)) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixDatagrams`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let (sock1, sock2) = match UnixDatagram::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; - Ok((UnixDatagram(i1), UnixDatagram(i2))) - } - - /// Connects the socket to the specified address. - /// - /// The [`send`] method may be used to send data to the specified address. - /// [`recv`] and [`recv_from`] will only receive data from that address. - /// - /// [`send`]: UnixDatagram::send - /// [`recv`]: UnixDatagram::recv - /// [`recv_from`]: UnixDatagram::recv_from - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// match sock.connect("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return Err(e) - /// } - /// }; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(&self, path: P) -> io::Result<()> { - fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; - - Ok(()) - } - } - inner(self, path.as_ref()) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixDatagram` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one side will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let sock_copy = sock.try_clone().expect("try_clone failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixDatagram) - } - - /// Returns the address of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let addr = sock.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the address of this socket's peer. - /// - /// The [`connect`] method will connect the socket to a peer. - /// - /// [`connect`]: UnixDatagram::connect - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.connect("/path/to/the/socket")?; - /// - /// let addr = sock.peer_addr().expect("Couldn't get peer address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) - } - - fn recv_from_flags( - &self, - buf: &mut [u8], - flags: libc::c_int, - ) -> io::Result<(usize, SocketAddr)> { - let mut count = 0; - let addr = SocketAddr::new(|addr, len| unsafe { - count = libc::recvfrom( - *self.0.as_inner(), - buf.as_mut_ptr() as *mut _, - buf.len(), - flags, - addr, - len, - ); - if count > 0 { - 1 - } else if count == 0 { - 0 - } else { - -1 - } - })?; - - Ok((count as usize, addr)) - } - - /// Receives data from the socket. - /// - /// On success, returns the number of bytes read and the address from - /// whence the data came. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// let mut buf = vec![0; 10]; - /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?; - /// println!("received {} bytes from {:?}", size, sender); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_flags(buf, 0) - } - - /// Receives data from the socket. - /// - /// On success, returns the number of bytes read. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let mut buf = vec![0; 10]; - /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn recv(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - /// Sends data on the socket to the specified address. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { - fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - let count = cvt(libc::sendto( - *d.0.as_inner(), - buf.as_ptr() as *const _, - buf.len(), - MSG_NOSIGNAL, - &addr as *const _ as *const _, - len, - ))?; - Ok(count as usize) - } - } - inner(self, buf, path.as_ref()) - } - - /// Sends data on the socket to the socket's peer. - /// - /// The peer address may be set by the `connect` method, and this method - /// will return an error if the socket has not already been connected. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.connect("/some/sock").expect("Couldn't connect"); - /// sock.send(b"omelette au fromage").expect("send_to function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn send(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will - /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] - /// is passed to this method. - /// - /// [`recv`]: UnixDatagram::recv - /// [`recv_from`]: UnixDatagram::recv_from - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will - /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`send`]: UnixDatagram::send - /// [`send_to`]: UnixDatagram::send_to - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); - /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// if let Ok(Some(err)) = sock.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shut down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// use std::net::Shutdown; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } - - /// Receives data on the socket from the remote address to which it is - /// connected, without removing that data from the queue. On success, - /// returns the number of bytes peeked. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recv` system call. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::bind("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.0.peek(buf) - } - - /// Receives a single datagram message on the socket, without removing it from the - /// queue. On success, returns the number of bytes read and the origin. - /// - /// The function must be called with valid byte array `buf` of sufficient size to - /// hold the message bytes. If a message is too long to fit in the supplied buffer, - /// excess bytes may be discarded. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. - /// - /// Do not use this function to implement busy waiting, instead use `libc::poll` to - /// synchronize IO events on one or more sockets. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::bind("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_flags(buf, libc::MSG_PEEK) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixDatagram { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixDatagram { - unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { - UnixDatagram(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixDatagram { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} diff --git a/library/std/src/sys/unix/ext/net/addr.rs b/library/std/src/sys/unix/ext/net/addr.rs new file mode 100644 index 0000000000000..1f9036242eb59 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/addr.rs @@ -0,0 +1,226 @@ +use crate::ffi::OsStr; +use crate::os::unix::ffi::OsStrExt; +use crate::path::Path; +use crate::sys::cvt; +use crate::{ascii, fmt, io, mem}; + +// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? +#[cfg(not(unix))] +#[allow(non_camel_case_types)] +mod libc { + pub use libc::c_int; + pub type socklen_t = u32; + pub struct sockaddr; + #[derive(Clone)] + pub struct sockaddr_un; +} + +fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { + // Work with an actual instance of the type since using a null pointer is UB + let base = addr as *const _ as usize; + let path = &addr.sun_path as *const _ as usize; + path - base +} + +pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { + let mut addr: libc::sockaddr_un = mem::zeroed(); + addr.sun_family = libc::AF_UNIX as libc::sa_family_t; + + let bytes = path.as_os_str().as_bytes(); + + if bytes.contains(&0) { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "paths may not contain interior null bytes", + )); + } + + if bytes.len() >= addr.sun_path.len() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "path must be shorter than SUN_LEN", + )); + } + for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { + *dst = *src as libc::c_char; + } + // null byte for pathname addresses is already there because we zeroed the + // struct + + let mut len = sun_path_offset(&addr) + bytes.len(); + match bytes.get(0) { + Some(&0) | None => {} + Some(_) => len += 1, + } + Ok((addr, len as libc::socklen_t)) +} + +enum AddressKind<'a> { + Unnamed, + Pathname(&'a Path), + Abstract(&'a [u8]), +} + +struct AsciiEscaped<'a>(&'a [u8]); + +impl<'a> fmt::Display for AsciiEscaped<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "\"")?; + for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { + write!(fmt, "{}", byte as char)?; + } + write!(fmt, "\"") + } +} + +/// An address associated with a Unix socket. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::net::UnixListener; +/// +/// let socket = match UnixListener::bind("/tmp/sock") { +/// Ok(sock) => sock, +/// Err(e) => { +/// println!("Couldn't bind: {:?}", e); +/// return +/// } +/// }; +/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// ``` +#[derive(Clone)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct SocketAddr { + addr: libc::sockaddr_un, + len: libc::socklen_t, +} + +impl SocketAddr { + pub(super) fn new(f: F) -> io::Result + where + F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, + { + unsafe { + let mut addr: libc::sockaddr_un = mem::zeroed(); + let mut len = mem::size_of::() as libc::socklen_t; + cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; + SocketAddr::from_parts(addr, len) + } + } + + pub(super) fn from_parts( + addr: libc::sockaddr_un, + mut len: libc::socklen_t, + ) -> io::Result { + if len == 0 { + // When there is a datagram from unnamed unix socket + // linux returns zero bytes of address + len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address + } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "file descriptor did not correspond to a Unix socket", + )); + } + + Ok(SocketAddr { addr, len }) + } + + /// Returns `true` if the address is unnamed. + /// + /// # Examples + /// + /// A named address: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixListener::bind("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), false); + /// Ok(()) + /// } + /// ``` + /// + /// An unnamed address: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), true); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn is_unnamed(&self) -> bool { + if let AddressKind::Unnamed = self.address() { true } else { false } + } + + /// Returns the contents of this address if it is a `pathname` address. + /// + /// # Examples + /// + /// With a pathname: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// use std::path::Path; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixListener::bind("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// Ok(()) + /// } + /// ``` + /// + /// Without a pathname: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), None); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn as_pathname(&self) -> Option<&Path> { + if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } + } + + fn address(&self) -> AddressKind<'_> { + let len = self.len as usize - sun_path_offset(&self.addr); + let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; + + // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses + if len == 0 + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && self.addr.sun_path[0] == 0) + { + AddressKind::Unnamed + } else if self.addr.sun_path[0] == 0 { + AddressKind::Abstract(&path[1..len]) + } else { + AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) + } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.address() { + AddressKind::Unnamed => write!(fmt, "(unnamed)"), + AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), + AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), + } + } +} diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs new file mode 100644 index 0000000000000..2c91ba70dd0b5 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -0,0 +1,660 @@ +use super::{sockaddr_un, SocketAddr}; +use crate::convert::TryFrom; +use crate::io::{self, IoSliceMut}; +use crate::marker::PhantomData; +use crate::mem::{size_of, zeroed}; +use crate::os::unix::io::RawFd; +use crate::path::Path; +#[cfg(target_os = "android")] +use crate::ptr::eq; +use crate::ptr::read_unaligned; +use crate::slice::from_raw_parts; +use crate::sys::net::Socket; + +// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? +#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android")))] +#[allow(non_camel_case_types)] +mod libc { + pub use libc::c_int; + pub struct ucred; + pub struct cmsghdr; + pub type pid_t = i32; + pub type gid_t = u32; + pub type uid_t = u32; +} + +pub(super) fn recv_vectored_with_ancillary_from( + socket: &Socket, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, +) -> io::Result<(usize, bool, io::Result)> { + unsafe { + let mut msg_name: libc::sockaddr_un = zeroed(); + + let mut msg: libc::msghdr = zeroed(); + msg.msg_name = &mut msg_name as *mut _ as *mut _; + msg.msg_namelen = size_of::() as libc::socklen_t; + msg.msg_iov = bufs.as_mut_ptr().cast(); + msg.msg_control = ancillary.buffer.as_mut_ptr().cast(); + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_iovlen = bufs.len() as libc::size_t; + msg.msg_controllen = ancillary.buffer.len() as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_iovlen = bufs.len() as libc::c_int; + msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t; + } + } + + let count = socket.recv_msg(&mut msg)?; + + ancillary.length = msg.msg_controllen as usize; + ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC; + + let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC; + let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen); + + Ok((count, truncated, addr)) + } +} + +pub(super) fn send_vectored_with_ancillary_to( + socket: &Socket, + path: Option<&Path>, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, +) -> io::Result { + unsafe { + let (mut msg_name, msg_namelen) = + if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) }; + + let mut msg: libc::msghdr = zeroed(); + msg.msg_name = &mut msg_name as *mut _ as *mut _; + msg.msg_namelen = msg_namelen; + msg.msg_iov = bufs.as_mut_ptr().cast(); + msg.msg_control = ancillary.buffer.as_mut_ptr().cast(); + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_iovlen = bufs.len() as libc::size_t; + msg.msg_controllen = ancillary.length as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_iovlen = bufs.len() as libc::c_int; + msg.msg_controllen = ancillary.length as libc::socklen_t; + } + } + + ancillary.truncated = false; + + socket.send_msg(&mut msg) + } +} + +fn add_to_ancillary_data( + buffer: &mut [u8], + length: &mut usize, + source: &[T], + cmsg_level: libc::c_int, + cmsg_type: libc::c_int, +) -> bool { + let source_len = if let Some(source_len) = source.len().checked_mul(size_of::()) { + if let Ok(source_len) = u32::try_from(source_len) { + source_len + } else { + return false; + } + } else { + return false; + }; + + unsafe { + let additional_space = libc::CMSG_SPACE(source_len) as usize; + + let new_length = if let Some(new_length) = additional_space.checked_add(*length) { + new_length + } else { + return false; + }; + + if new_length > buffer.len() { + return false; + } + + buffer[*length..new_length].fill(0); + + *length = new_length; + + let mut msg: libc::msghdr = zeroed(); + msg.msg_control = buffer.as_mut_ptr().cast(); + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_controllen = *length as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_controllen = *length as libc::socklen_t; + } + } + + let mut cmsg = libc::CMSG_FIRSTHDR(&msg); + let mut previous_cmsg = cmsg; + while !cmsg.is_null() { + previous_cmsg = cmsg; + cmsg = libc::CMSG_NXTHDR(&msg, cmsg); + cfg_if::cfg_if! { + // Android return the same pointer if it is the last cmsg. + // Therefore, check it if the previous pointer is the same as the current one. + if #[cfg(target_os = "android")] { + if cmsg == previous_cmsg { + break; + } + } + } + } + + if previous_cmsg.is_null() { + return false; + } + + (*previous_cmsg).cmsg_level = cmsg_level; + (*previous_cmsg).cmsg_type = cmsg_type; + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::socklen_t; + } + } + + let data = libc::CMSG_DATA(previous_cmsg).cast(); + + libc::memcpy(data, source.as_ptr().cast(), source_len as usize); + } + true +} + +struct AncillaryDataIter<'a, T> { + data: &'a [u8], + phantom: PhantomData, +} + +impl<'a, T> AncillaryDataIter<'a, T> { + /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message. + /// + /// # Safety + /// + /// `data` must contain a valid control message. + unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> { + AncillaryDataIter { data, phantom: PhantomData } + } +} + +impl<'a, T> Iterator for AncillaryDataIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + if size_of::() <= self.data.len() { + unsafe { + let unit = read_unaligned(self.data.as_ptr().cast()); + self.data = &self.data[size_of::()..]; + Some(unit) + } + } else { + None + } + } +} + +/// Unix credential. +#[cfg(any(doc, target_os = "android", target_os = "linux",))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +#[derive(Clone)] +pub struct SocketCred(libc::ucred); + +#[cfg(any(doc, target_os = "android", target_os = "linux",))] +impl SocketCred { + /// Create a Unix credential struct. + /// + /// PID, UID and GID is set to 0. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn new() -> SocketCred { + SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) + } + + /// Set the PID. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn set_pid(&mut self, pid: libc::pid_t) { + self.0.pid = pid; + } + + /// Get the current PID. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn get_pid(&self) -> libc::pid_t { + self.0.pid + } + + /// Set the UID. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn set_uid(&mut self, uid: libc::uid_t) { + self.0.uid = uid; + } + + /// Get the current UID. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn get_uid(&self) -> libc::uid_t { + self.0.uid + } + + /// Set the GID. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn set_gid(&mut self, gid: libc::gid_t) { + self.0.gid = gid; + } + + /// Get the current GID. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn get_gid(&self) -> libc::gid_t { + self.0.gid + } +} + +/// This control message contains file descriptors. +/// +/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`. +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>); + +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +impl<'a> Iterator for ScmRights<'a> { + type Item = RawFd; + + fn next(&mut self) -> Option { + self.0.next() + } +} + +/// This control message contains unix credentials. +/// +/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`. +#[cfg(any(doc, target_os = "android", target_os = "linux",))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); + +#[cfg(any(doc, target_os = "android", target_os = "linux",))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +impl<'a> Iterator for ScmCredentials<'a> { + type Item = SocketCred; + + fn next(&mut self) -> Option { + Some(SocketCred(self.0.next()?)) + } +} + +/// The error type which is returned from parsing the type a control message. +#[non_exhaustive] +#[derive(Debug)] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +pub enum AncillaryError { + Unknown { cmsg_level: i32, cmsg_type: i32 }, +} + +/// This enum represent one control message of variable type. +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +pub enum AncillaryData<'a> { + ScmRights(ScmRights<'a>), + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + ScmCredentials(ScmCredentials<'a>), +} + +impl<'a> AncillaryData<'a> { + /// Create a `AncillaryData::ScmRights` variant. + /// + /// # Safety + /// + /// `data` must contain a valid control message and the control message must be type of + /// `SOL_SOCKET` and level of `SCM_RIGHTS`. + unsafe fn as_rights(data: &'a [u8]) -> Self { + let ancillary_data_iter = AncillaryDataIter::new(data); + let scm_rights = ScmRights(ancillary_data_iter); + AncillaryData::ScmRights(scm_rights) + } + + /// Create a `AncillaryData::ScmCredentials` variant. + /// + /// # Safety + /// + /// `data` must contain a valid control message and the control message must be type of + /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`. + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + unsafe fn as_credentials(data: &'a [u8]) -> Self { + let ancillary_data_iter = AncillaryDataIter::new(data); + let scm_credentials = ScmCredentials(ancillary_data_iter); + AncillaryData::ScmCredentials(scm_credentials) + } + + fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result { + unsafe { + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + let cmsg_len_zero = libc::CMSG_LEN(0) as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + let cmsg_len_zero = libc::CMSG_LEN(0) as libc::socklen_t; + } + } + let data_len = (*cmsg).cmsg_len - cmsg_len_zero; + let data = libc::CMSG_DATA(cmsg).cast(); + let data = from_raw_parts(data, data_len as usize); + + match (*cmsg).cmsg_level { + libc::SOL_SOCKET => match (*cmsg).cmsg_type { + libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)), + #[cfg(any(target_os = "android", target_os = "linux",))] + libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)), + cmsg_type => { + Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type }) + } + }, + cmsg_level => { + Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type }) + } + } + } + } +} + +/// This struct is used to iterate through the control messages. +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +pub struct Messages<'a> { + buffer: &'a [u8], + current: Option<&'a libc::cmsghdr>, +} + +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +impl<'a> Iterator for Messages<'a> { + type Item = Result, AncillaryError>; + + fn next(&mut self) -> Option { + unsafe { + let mut msg: libc::msghdr = zeroed(); + msg.msg_control = self.buffer.as_ptr() as *mut _; + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_controllen = self.buffer.len() as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_controllen = self.buffer.len() as libc::socklen_t; + } + } + + let cmsg = if let Some(current) = self.current { + libc::CMSG_NXTHDR(&msg, current) + } else { + libc::CMSG_FIRSTHDR(&msg) + }; + + let cmsg = cmsg.as_ref()?; + cfg_if::cfg_if! { + // Android return the same pointer if it is the last cmsg. + // Therefore, check it if the previous pointer is the same as the current one. + if #[cfg(target_os = "android")] { + if let Some(current) = self.current { + if eq(current, cmsg) { + return None; + } + } + } + } + + self.current = Some(cmsg); + let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg); + Some(ancillary_result) + } + } +} + +/// A Unix socket Ancillary data struct. +/// +/// # Example +/// ```no_run +/// #![feature(unix_socket_ancillary_data)] +/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; +/// use std::io::IoSliceMut; +/// +/// fn main() -> std::io::Result<()> { +/// let sock = UnixStream::connect("/tmp/sock")?; +/// +/// let mut fds = [0; 8]; +/// let mut ancillary_buffer = [0; 128]; +/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); +/// +/// let mut buf = [1; 8]; +/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; +/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; +/// +/// for ancillary_result in ancillary.messages() { +/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { +/// for fd in scm_rights { +/// println!("receive file descriptor: {}", fd); +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +#[derive(Debug)] +pub struct SocketAncillary<'a> { + buffer: &'a mut [u8], + length: usize, + truncated: bool, +} + +impl<'a> SocketAncillary<'a> { + /// Create an ancillary data with the given buffer. + /// + /// # Example + /// + /// ```no_run + /// # #![allow(unused_mut)] + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::SocketAncillary; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn new(buffer: &'a mut [u8]) -> Self { + SocketAncillary { buffer, length: 0, truncated: false } + } + + /// Returns the capacity of the buffer. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn capacity(&self) -> usize { + self.buffer.len() + } + + /// Returns the number of used bytes. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn len(&self) -> usize { + self.length + } + + /// Returns the iterator of the control messages. + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn messages(&self) -> Messages<'_> { + Messages { buffer: &self.buffer[..self.length], current: None } + } + + /// Is `true` if during a recv operation the ancillary was truncated. + /// + /// # Example + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// + /// let mut buf = [1; 8]; + /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// + /// println!("Is truncated: {}", ancillary.truncated()); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn truncated(&self) -> bool { + self.truncated + } + + /// Add file descriptors to the ancillary data. + /// + /// The function returns `true` if there was enough space in the buffer. + /// If there was not enough space then no file descriptors was appended. + /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` + /// and type `SCM_RIGHTS`. + /// + /// # Example + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary}; + /// use std::os::unix::io::AsRawFd; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&[sock.as_raw_fd()][..]); + /// + /// let mut buf = [1; 8]; + /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn add_fds(&mut self, fds: &[RawFd]) -> bool { + self.truncated = false; + add_to_ancillary_data( + &mut self.buffer, + &mut self.length, + fds, + libc::SOL_SOCKET, + libc::SCM_RIGHTS, + ) + } + + /// Add credentials to the ancillary data. + /// + /// The function returns `true` if there was enough space in the buffer. + /// If there was not enough space then no credentials was appended. + /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` + /// and type `SCM_CREDENTIALS` or `SCM_CREDS`. + /// + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool { + self.truncated = false; + add_to_ancillary_data( + &mut self.buffer, + &mut self.length, + creds, + libc::SOL_SOCKET, + libc::SCM_CREDENTIALS, + ) + } + + /// Clears the ancillary data, removing all values. + /// + /// # Example + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// + /// let mut fds1 = [0; 8]; + /// let mut fds2 = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// + /// let mut buf = [1; 8]; + /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// + /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// + /// ancillary.clear(); + /// + /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn clear(&mut self) { + self.length = 0; + self.truncated = false; + } +} diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs new file mode 100644 index 0000000000000..0f532c47c8f92 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -0,0 +1,897 @@ +#[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary}; +use super::{sockaddr_un, SocketAddr}; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +use crate::io::IoSliceMut; +use crate::net::Shutdown; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::path::Path; +use crate::sys::cvt; +use crate::sys::net::Socket; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::time::Duration; +use crate::{fmt, io}; + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "haiku" +))] +use libc::MSG_NOSIGNAL; +#[cfg(not(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "haiku" +)))] +const MSG_NOSIGNAL: libc::c_int = 0x0; + +/// A Unix datagram socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixDatagram; +/// +/// fn main() -> std::io::Result<()> { +/// let socket = UnixDatagram::bind("/path/to/my/socket")?; +/// socket.send_to(b"hello world", "/path/to/other/socket")?; +/// let mut buf = [0; 100]; +/// let (count, address) = socket.recv_from(&mut buf)?; +/// println!("socket {:?} sent {:?}", address, &buf[..count]); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixDatagram(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixDatagram { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixDatagram"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixDatagram { + /// Creates a Unix datagram socket bound to the given path. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let sock = match UnixDatagram::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't bind: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + unsafe { + let socket = UnixDatagram::unbound()?; + let (addr, len) = sockaddr_un(path.as_ref())?; + + cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; + + Ok(socket) + } + } + + /// Creates a Unix Datagram socket which is not bound to any address. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let sock = match UnixDatagram::unbound() { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't unbound: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn unbound() -> io::Result { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; + Ok(UnixDatagram(inner)) + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixDatagrams`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let (sock1, sock2) = match UnixDatagram::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't unbound: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { + let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; + Ok((UnixDatagram(i1), UnixDatagram(i2))) + } + + /// Connects the socket to the specified address. + /// + /// The [`send`] method may be used to send data to the specified address. + /// [`recv`] and [`recv_from`] will only receive data from that address. + /// + /// [`send`]: UnixDatagram::send + /// [`recv`]: UnixDatagram::recv + /// [`recv_from`]: UnixDatagram::recv_from + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// match sock.connect("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return Err(e) + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(&self, path: P) -> io::Result<()> { + unsafe { + let (addr, len) = sockaddr_un(path.as_ref())?; + + cvt(libc::connect(*self.0.as_inner(), &addr as *const _ as *const _, len))?; + } + Ok(()) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixDatagram` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one side will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let sock_copy = sock.try_clone().expect("try_clone failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixDatagram) + } + + /// Returns the address of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let addr = sock.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Returns the address of this socket's peer. + /// + /// The [`connect`] method will connect the socket to a peer. + /// + /// [`connect`]: UnixDatagram::connect + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.connect("/path/to/the/socket")?; + /// + /// let addr = sock.peer_addr().expect("Couldn't get peer address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + } + + fn recv_from_flags( + &self, + buf: &mut [u8], + flags: libc::c_int, + ) -> io::Result<(usize, SocketAddr)> { + let mut count = 0; + let addr = SocketAddr::new(|addr, len| unsafe { + count = libc::recvfrom( + *self.0.as_inner(), + buf.as_mut_ptr() as *mut _, + buf.len(), + flags, + addr, + len, + ); + if count > 0 { + 1 + } else if count == 0 { + 0 + } else { + -1 + } + })?; + + Ok((count as usize, addr)) + } + + /// Receives data from the socket. + /// + /// On success, returns the number of bytes read and the address from + /// whence the data came. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf = vec![0; 10]; + /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?; + /// println!("received {} bytes from {:?}", size, sender); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, 0) + } + + /// Receives data from the socket. + /// + /// On success, returns the number of bytes read. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let mut buf = vec![0; 10]; + /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn recv(&self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + /// Receives data and ancillary data from socket. + /// + /// On success, returns the number of bytes read, if the data was truncated and the address from whence the msg came. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let mut fds = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?; + /// println!("received {}", size); + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn recv_vectored_with_ancillary_from( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result<(usize, bool, SocketAddr)> { + let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; + let addr = addr?; + + Ok((count, truncated, addr)) + } + + /// Receives data and ancillary data from socket. + /// + /// On success, returns the number of bytes read and if the data was truncated. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let mut fds = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// println!("received {}", size); + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn recv_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result<(usize, bool)> { + let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; + addr?; + + Ok((count, truncated)) + } + + /// Sends data on the socket to the specified address. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { + unsafe { + let (addr, len) = sockaddr_un(path.as_ref())?; + + let count = cvt(libc::sendto( + *self.0.as_inner(), + buf.as_ptr() as *const _, + buf.len(), + MSG_NOSIGNAL, + &addr as *const _ as *const _, + len, + ))?; + Ok(count as usize) + } + } + + /// Sends data on the socket to the socket's peer. + /// + /// The peer address may be set by the `connect` method, and this method + /// will return an error if the socket has not already been connected. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.connect("/some/sock").expect("Couldn't connect"); + /// sock.send(b"omelette au fromage").expect("send_to function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn send(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + /// Sends data and ancillary data on the socket to the specified address. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let fds = [0, 1, 2]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&fds[..]); + /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock").expect("send_vectored_with_ancillary_to function failed"); + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn send_vectored_with_ancillary_to>( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + path: P, + ) -> io::Result { + send_vectored_with_ancillary_to(&self.0, Some(path.as_ref()), bufs, ancillary) + } + + /// Sends data and ancillary data on the socket. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let fds = [0, 1, 2]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&fds[..]); + /// sock.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn send_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result { + send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] + /// is passed to this method. + /// + /// [`recv`]: UnixDatagram::recv + /// [`recv_from`]: UnixDatagram::recv_from + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_read_timeout(Some(Duration::new(1, 0))) + /// .expect("set_read_timeout function failed"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`send`]: UnixDatagram::send + /// [`send_to`]: UnixDatagram::send_to + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("set_write_timeout function failed"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_read_timeout(Some(Duration::new(1, 0))) + /// .expect("set_read_timeout function failed"); + /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_RCVTIMEO) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("set_write_timeout function failed"); + /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_SNDTIMEO) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`]. + /// + /// Set the socket option `SO_PASSCRED`. + /// + /// # Examples + /// + #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")] + #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")] + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_passcred(true).expect("set_passcred function failed"); + /// Ok(()) + /// } + /// ``` + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + self.0.set_passcred(passcred) + } + + /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`]. + /// This value can be change by [`set_passcred`]. + /// + /// Get the socket option `SO_PASSCRED`. + /// + /// [`set_passcred`]: UnixDatagram::set_passcred + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn passcred(&self) -> io::Result { + self.0.passcred() + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// if let Ok(Some(err)) = sock.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Shut down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// use std::net::Shutdown; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + + /// Receives a single datagram message on the socket, without removing it from the + /// queue. On success, returns the number of bytes read and the origin. + /// + /// The function must be called with valid byte array `buf` of sufficient size to + /// hold the message bytes. If a message is too long to fit in the supplied buffer, + /// excess bytes may be discarded. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. + /// + /// Do not use this function to implement busy waiting, instead use `libc::poll` to + /// synchronize IO events on one or more sockets. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, libc::MSG_PEEK) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixDatagram { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixDatagram { + unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { + UnixDatagram(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixDatagram { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} diff --git a/library/std/src/sys/unix/ext/net/listener.rs b/library/std/src/sys/unix/ext/net/listener.rs new file mode 100644 index 0000000000000..9803c6e27462c --- /dev/null +++ b/library/std/src/sys/unix/ext/net/listener.rs @@ -0,0 +1,319 @@ +use super::{sockaddr_un, SocketAddr, UnixStream}; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::path::Path; +use crate::sys::cvt; +use crate::sys::net::Socket; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::{fmt, io, mem}; + +/// A structure representing a Unix domain socket server. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// fn main() -> std::io::Result<()> { +/// let listener = UnixListener::bind("/path/to/the/socket")?; +/// +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// /* connection succeeded */ +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// /* connection failed */ +/// break; +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixListener(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixListener { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixListener"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + builder.finish() + } +} + +impl UnixListener { + /// Creates a new `UnixListener` bound to the specified socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = match UnixListener::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path.as_ref())?; + + cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(libc::listen(*inner.as_inner(), 128))?; + + Ok(UnixListener(inner)) + } + } + + /// Accepts a new incoming connection to this listener. + /// + /// This function will block the calling thread until a new Unix connection + /// is established. When established, the corresponding [`UnixStream`] and + /// the remote peer's address will be returned. + /// + /// [`UnixStream`]: crate::os::unix::net::UnixStream + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// + /// match listener.accept() { + /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), + /// Err(e) => println!("accept function failed: {:?}", e), + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; + let mut len = mem::size_of_val(&storage) as libc::socklen_t; + let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; + let addr = SocketAddr::from_parts(storage, len)?; + Ok((UnixStream(sock), addr)) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixListener` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one listener will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixListener) + } + + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// This will result in the `accept` operation becoming nonblocking, + /// i.e., immediately returning from their calls. If the IO operation is + /// successful, `Ok` is returned and no further action is required. If the + /// IO operation could not be completed and needs to be retried, an error + /// with kind [`io::ErrorKind::WouldBlock`] is returned. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/tmp/sock")?; + /// + /// if let Ok(Some(err)) = listener.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns `None`. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Returns an iterator over incoming connections. + /// + /// The iterator will never return [`None`] and will also not yield the + /// peer's [`SocketAddr`] structure. + /// + /// # Examples + /// + /// ```no_run + /// use std::thread; + /// use std::os::unix::net::{UnixStream, UnixListener}; + /// + /// fn handle_client(stream: UnixStream) { + /// // ... + /// } + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// thread::spawn(|| handle_client(stream)); + /// } + /// Err(err) => { + /// break; + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn incoming(&self) -> Incoming<'_> { + Incoming { listener: self } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> IntoIterator for &'a UnixListener { + type Item = io::Result; + type IntoIter = Incoming<'a>; + + fn into_iter(self) -> Incoming<'a> { + self.incoming() + } +} + +/// An iterator over incoming connections to a [`UnixListener`]. +/// +/// It will never return [`None`]. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// fn main() -> std::io::Result<()> { +/// let listener = UnixListener::bind("/path/to/the/socket")?; +/// +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// break; +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[derive(Debug)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct Incoming<'a> { + listener: &'a UnixListener, +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|s| s.0)) + } + + fn size_hint(&self) -> (usize, Option) { + (usize::MAX, None) + } +} diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs new file mode 100644 index 0000000000000..3088ffb5e5c01 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -0,0 +1,54 @@ +//! Unix-specific networking functionality + +#![stable(feature = "unix_socket", since = "1.10.0")] + +mod addr; +#[doc(cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +)))] +#[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +mod ancillary; +mod datagram; +mod listener; +mod raw_fd; +mod stream; +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::addr::*; +#[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +pub use self::ancillary::*; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::datagram::*; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::listener::*; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::raw_fd::*; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::stream::*; diff --git a/library/std/src/sys/unix/ext/net/raw_fd.rs b/library/std/src/sys/unix/ext/net/raw_fd.rs new file mode 100644 index 0000000000000..c42fee4c73bcd --- /dev/null +++ b/library/std/src/sys/unix/ext/net/raw_fd.rs @@ -0,0 +1,40 @@ +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::sys_common::{self, AsInner, FromInner, IntoInner}; +use crate::{net, sys}; + +macro_rules! impl_as_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl AsRawFd for net::$t { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } + } + )*}; +} +impl_as_raw_fd! { TcpStream TcpListener UdpSocket } + +macro_rules! impl_from_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "from_raw_os", since = "1.1.0")] + impl FromRawFd for net::$t { + unsafe fn from_raw_fd(fd: RawFd) -> net::$t { + let socket = sys::net::Socket::from_inner(fd); + net::$t::from_inner(sys_common::net::$t::from_inner(socket)) + } + } + )*}; +} +impl_from_raw_fd! { TcpStream TcpListener UdpSocket } + +macro_rules! impl_into_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "into_raw_os", since = "1.4.0")] + impl IntoRawFd for net::$t { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } + } + )*}; +} +impl_into_raw_fd! { TcpStream TcpListener UdpSocket } diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs new file mode 100644 index 0000000000000..9fe6b85837e33 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -0,0 +1,673 @@ +#[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary}; +use super::{sockaddr_un, SocketAddr}; +use crate::fmt; +use crate::io::{self, Initializer, IoSlice, IoSliceMut}; +use crate::net::Shutdown; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +use crate::os::unix::ucred; +use crate::path::Path; +use crate::sys::cvt; +use crate::sys::net::Socket; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::time::Duration; + +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub use ucred::UCred; + +/// A Unix stream socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixStream; +/// use std::io::prelude::*; +/// +/// fn main() -> std::io::Result<()> { +/// let mut stream = UnixStream::connect("/path/to/my/socket")?; +/// stream.write_all(b"hello world")?; +/// let mut response = String::new(); +/// stream.read_to_string(&mut response)?; +/// println!("{}", response); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixStream(pub(super) Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixStream { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixStream"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixStream { + /// Connects to the socket named by `path`. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = match UnixStream::connect("/tmp/sock") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(path: P) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path.as_ref())?; + + cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; + Ok(UnixStream(inner)) + } + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixStream`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let (sock1, sock2) = match UnixStream::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't create a pair of sockets: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { + let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; + Ok((UnixStream(i1), UnixStream(i2))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixStream) + } + + /// Returns the socket address of the local half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Returns the socket address of the remote half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + } + + /// Gets the peer credentials for this Unix domain socket. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(peer_credentials_unix_socket)] + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" + ))] + pub fn peer_cred(&self) -> io::Result { + ucred::peer_cred(self) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`read`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`read`]: io::Read::read + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`write`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. + /// + /// [`read`]: io::Read::read + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("Couldn't set write timeout"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UdpSocket::bind("127.0.0.1:34254")?; + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_RCVTIMEO) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_SNDTIMEO) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`]. + /// + /// Set the socket option `SO_PASSCRED`. + /// + /// # Examples + /// + #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")] + #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")] + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_passcred(true).expect("Couldn't set passcred"); + /// Ok(()) + /// } + /// ``` + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + self.0.set_passcred(passcred) + } + + /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`]. + /// This value can be change by [`set_passcred`]. + /// + /// Get the socket option `SO_PASSCRED`. + /// + /// [`set_passcred`]: UnixStream::set_passcred + #[cfg(any(doc, target_os = "android", target_os = "linux",))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn passcred(&self) -> io::Result { + self.0.passcred() + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// if let Ok(Some(err)) = socket.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns `None`. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::net::Shutdown; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + + /// Receives data and ancillary data from socket. + /// + /// On success, returns the number of bytes read. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let mut fds = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// println!("received {}", size); + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn recv_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result { + let (count, _, _) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; + + Ok(count) + } + + /// Sends data and ancillary data on the socket. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let fds = [0, 1, 2]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&fds[..]); + /// socket.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] + pub fn send_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result { + send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Read for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + io::Read::read(&mut &*self, buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + io::Read::read_vectored(&mut &*self, bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + io::Read::is_read_vectored(&&*self) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Write for UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + io::Write::write(&mut &*self, buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + io::Write::write_vectored(&mut &*self, bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &*self) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index ee73a6ed538ff..97a016904b4a4 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -1,11 +1,30 @@ +use super::*; use crate::io::prelude::*; -use crate::io::{self, ErrorKind}; +use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +use crate::iter::FromIterator; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +use crate::os::unix::io::AsRawFd; use crate::sys_common::io::test::tmpdir; use crate::thread; use crate::time::Duration; -use super::*; - macro_rules! or_panic { ($e:expr) => { match $e { @@ -452,3 +471,170 @@ fn test_unix_datagram_peek_from() { assert_eq!(size, 11); assert_eq!(msg, &buf[..]); } + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +#[test] +fn test_send_vectored_fds_unix_stream() { + let (s1, s2) = or_panic!(UnixStream::pair()); + + let mut buf1 = [1; 8]; + let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + + let mut ancillary1_buffer = [0; 128]; + let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); + assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..])); + + let usize = or_panic!(s1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); + assert_eq!(usize, 8); + + let mut buf2 = [0; 8]; + let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; + + let mut ancillary2_buffer = [0; 128]; + let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); + + let usize = or_panic!(s2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2)); + assert_eq!(usize, 8); + assert_eq!(buf1, buf2); + + let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); + assert_eq!(ancillary_data_vec.len(), 1); + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { + let fd_vec = Vec::from_iter(scm_rights); + assert_eq!(fd_vec.len(), 1); + unsafe { + libc::close(fd_vec[0]); + } + } else { + unreachable!("must be ScmRights"); + } +} + +#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[test] +fn test_send_vectored_with_ancillary_to_unix_datagram() { + fn getpid() -> libc::pid_t { + unsafe { libc::getpid() } + } + + fn getuid() -> libc::uid_t { + unsafe { libc::getuid() } + } + + fn getgid() -> libc::gid_t { + unsafe { libc::getgid() } + } + + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let bsock1 = or_panic!(UnixDatagram::bind(&path1)); + let bsock2 = or_panic!(UnixDatagram::bind(&path2)); + + or_panic!(bsock2.set_passcred(true)); + + let mut buf1 = [1; 8]; + let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + + let mut ancillary1_buffer = [0; 128]; + let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); + let mut cred1 = SocketCred::new(); + cred1.set_pid(getpid()); + cred1.set_uid(getuid()); + cred1.set_gid(getgid()); + assert!(ancillary1.add_creds(&[cred1.clone()][..])); + + let usize = + or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2)); + assert_eq!(usize, 8); + + let mut buf2 = [0; 8]; + let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; + + let mut ancillary2_buffer = [0; 128]; + let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); + + let (usize, truncated, _addr) = + or_panic!(bsock2.recv_vectored_with_ancillary_from(&mut bufs_recv, &mut ancillary2)); + assert_eq!(ancillary2.truncated(), false); + assert_eq!(usize, 8); + assert_eq!(truncated, false); + assert_eq!(buf1, buf2); + + let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); + assert_eq!(ancillary_data_vec.len(), 1); + if let AncillaryData::ScmCredentials(scm_credentials) = + ancillary_data_vec.pop().unwrap().unwrap() + { + let cred_vec = Vec::from_iter(scm_credentials); + assert_eq!(cred_vec.len(), 1); + assert_eq!(cred1.get_pid(), cred_vec[0].get_pid()); + assert_eq!(cred1.get_uid(), cred_vec[0].get_uid()); + assert_eq!(cred1.get_gid(), cred_vec[0].get_gid()); + } else { + unreachable!("must be ScmCredentials"); + } +} + +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +#[test] +fn test_send_vectored_with_ancillary_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let bsock1 = or_panic!(UnixDatagram::bind(&path1)); + let bsock2 = or_panic!(UnixDatagram::bind(&path2)); + + let mut buf1 = [1; 8]; + let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + + let mut ancillary1_buffer = [0; 128]; + let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); + assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..])); + + or_panic!(bsock1.connect(&path2)); + let usize = or_panic!(bsock1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); + assert_eq!(usize, 8); + + let mut buf2 = [0; 8]; + let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; + + let mut ancillary2_buffer = [0; 128]; + let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); + + let (usize, truncated) = + or_panic!(bsock2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2)); + assert_eq!(usize, 8); + assert_eq!(truncated, false); + assert_eq!(buf1, buf2); + + let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); + assert_eq!(ancillary_data_vec.len(), 1); + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { + let fd_vec = Vec::from_iter(scm_rights); + assert_eq!(fd_vec.len(), 1); + unsafe { + libc::close(fd_vec[0]); + } + } else { + unreachable!("must be ScmRights"); + } +} diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 378d690f8bfd7..7198a2f08d668 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -275,6 +275,20 @@ impl Socket { self.recv_from_with_flags(buf, 0) } + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result { + let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?; + Ok(n as usize) + } + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { self.recv_from_with_flags(buf, MSG_PEEK) } @@ -292,6 +306,20 @@ impl Socket { self.0.is_write_vectored() } + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result { + let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?; + Ok(n as usize) + } + pub fn set_timeout(&self, dur: Option, kind: libc::c_int) -> io::Result<()> { let timeout = match dur { Some(dur) => { @@ -351,6 +379,17 @@ impl Socket { Ok(raw != 0) } + #[cfg(any(target_os = "android", target_os = "linux",))] + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) + } + + #[cfg(any(target_os = "android", target_os = "linux",))] + pub fn passcred(&self) -> io::Result { + let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?; + Ok(passcred != 0) + } + #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let mut nonblocking = nonblocking as libc::c_int; diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs index 0e55ec648c9c5..76056637a4cf9 100644 --- a/library/std/tests/env.rs +++ b/library/std/tests/env.rs @@ -1,6 +1,5 @@ use std::env::*; use std::ffi::{OsStr, OsString}; -use std::path::PathBuf; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; @@ -92,6 +91,8 @@ fn env_home_dir() { cfg_if::cfg_if! { if #[cfg(unix)] { + use std::path::PathBuf; + let oldhome = var_to_os_string(var("HOME")); set_var("HOME", "/home/MountainView"); @@ -109,6 +110,8 @@ fn env_home_dir() { if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } } else if #[cfg(windows)] { + use std::path::PathBuf; + let oldhome = var_to_os_string(var("HOME")); let olduserprofile = var_to_os_string(var("USERPROFILE")); diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index b5bbb6372ee6c..6d97943548d5a 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -425,6 +425,7 @@ impl<'a> Builder<'a> { test::RustdocJSNotStd, test::RustdocTheme, test::RustdocUi, + test::RustdocJson, // Run bootstrap close to the end as it's unlikely to fail test::Bootstrap, // Run run-make last, since these won't pass without make on Windows diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 1df50322a0732..78b5de7897d1f 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -904,6 +904,12 @@ host_test!(UiFullDeps { path: "src/test/ui-fulldeps", mode: "ui", suite: "ui-ful host_test!(Rustdoc { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" }); host_test!(RustdocUi { path: "src/test/rustdoc-ui", mode: "ui", suite: "rustdoc-ui" }); +host_test!(RustdocJson { + path: "src/test/rustdoc-json", + mode: "rustdoc-json", + suite: "rustdoc-json" +}); + host_test!(Pretty { path: "src/test/pretty", mode: "pretty", suite: "pretty" }); default_test!(RunMake { path: "src/test/run-make", mode: "run-make", suite: "run-make" }); @@ -1001,6 +1007,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the || (mode == "run-make" && suite.ends_with("fulldeps")) || (mode == "ui" && is_rustdoc) || mode == "js-doc-test" + || mode == "rustdoc-json" { cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler)); } diff --git a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md index 1dd7272e0f92a..9930bc67cd5d2 100644 --- a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md +++ b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md @@ -1,8 +1,6 @@ # `source-based-code-coverage` -The feature request for this feature is: [#34701] - -The Major Change Proposal (MCP) for this feature is: [#278](https://github.com/rust-lang/compiler-team/issues/278) +The tracking issue for this feature is: [#79121]. ------------------------ @@ -10,7 +8,7 @@ The Major Change Proposal (MCP) for this feature is: [#278](https://github.com/r The Rust compiler includes two code coverage implementations: -* A GCC-compatible, gcov-based coverage implementation, enabled with [`-Zprofile`](profile.md), which operates on DebugInfo. +* A GCC-compatible, gcov-based coverage implementation, enabled with [`-Zprofile`], which operates on DebugInfo. * A source-based code coverage implementation, enabled with `-Zinstrument-coverage`, which uses LLVM's native coverage instrumentation to generate very precise coverage data. This document describes how to enable and use the LLVM instrumentation-based coverage, via the `-Zinstrument-coverage` compiler flag. @@ -20,7 +18,7 @@ This document describes how to enable and use the LLVM instrumentation-based cov When `-Zinstrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by: * Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed. -* Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format]), to define the code regions (start and end positions in the source code) being counted. +* Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 4_, supported _only_ in LLVM 11 and up), to define the code regions (start and end positions in the source code) being counted. When running a coverage-instrumented program, the counter values are written to a `profraw` file at program termination. LLVM bundles tools that read the counter results, combine those results with the coverage map (embedded in the program binary), and generate coverage reports in multiple formats. @@ -30,7 +28,7 @@ Rust's source-based code coverage requires the Rust "profiler runtime". Without The Rust `nightly` distribution channel should include the profiler runtime, by default. -*IMPORTANT:* If you are building the Rust compiler from the source distribution, the profiler runtime is *not* enabled in the default `config.toml.example`, and may not be enabled in your `config.toml`. Edit the `config.toml` file, and find the `profiler` feature entry. Uncomment it and set it to `true`: +*IMPORTANT:* If you are building the Rust compiler from the source distribution, the profiler runtime is *not* enabled in the default `config.toml.example`. Edit your `config.toml` file and ensure the `profiler` feature is set it to `true`: ```toml # Build the profiler runtime (required when compiling with options that depend @@ -38,13 +36,13 @@ The Rust `nightly` distribution channel should include the profiler runtime, by profiler = true ``` -Then rebuild the Rust compiler (see [rustc-dev-guide-how-to-build-and-run]). +If changed, rebuild the Rust compiler (see [rustc-dev-guide-how-to-build-and-run]). ### Building the demangler LLVM coverage reporting tools generate results that can include function names and other symbol references, and the raw coverage results report symbols using the compiler's "mangled" version of the symbol names, which can be difficult to interpret. To work around this issue, LLVM coverage tools also support a user-specified symbol name demangler. -One option for a Rust demangler is [`rustfilt`](https://crates.io/crates/rustfilt), which can be installed with: +One option for a Rust demangler is [`rustfilt`], which can be installed with: ```shell cargo install rustfilt @@ -70,7 +68,7 @@ $ cargo clean $ RUSTFLAGS="-Zinstrument-coverage" cargo build ``` -If `cargo` is not configured to use your `profiler`-enabled version of `rustc`, set the path explicitly via the `RUSTC` environment variable. Here is another example, using a `stage1` build of `rustc` to compile an `example` binary (from the [`json5format`](https://crates.io/crates/json5format) crate): +If `cargo` is not configured to use your `profiler`-enabled version of `rustc`, set the path explicitly via the `RUSTC` environment variable. Here is another example, using a `stage1` build of `rustc` to compile an `example` binary (from the [`json5format`] crate): ```shell $ RUSTC=$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc \ @@ -78,6 +76,8 @@ $ RUSTC=$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc \ cargo build --example formatjson5 ``` +Note that some compiler options, combined with `-Zinstrument-coverage`, can produce LLVM IR and/or linked binaries that are incompatible with LLVM coverage maps. For example, coverage requires references to actual functions in LLVM IR. If any covered function is optimized out, the coverage tools may not be able to process the coverage results. If you need to pass additional options, with coverage enabled, test them early, to confirm you will get the coverage results you expect. + ## Running the instrumented binary to generate raw coverage profiling data In the previous example, `cargo` generated the coverage-instrumented binary `formatjson5`: @@ -110,19 +110,31 @@ If `LLVM_PROFILE_FILE` contains a path to a non-existent directory, the missing * `%Nm` - the instrumented binary’s signature: The runtime creates a pool of N raw profiles, used for on-line profile merging. The runtime takes care of selecting a raw profile from the pool, locking it, and updating it before the program exits. `N` must be between `1` and `9`, and defaults to `1` if omitted (with simply `%m`). * `%c` - Does not add anything to the filename, but enables a mode (on some platforms, including Darwin) in which profile counter updates are continuously synced to a file. This means that if the instrumented program crashes, or is killed by a signal, perfect coverage information can still be recovered. -## Creating coverage reports +## Installing LLVM coverage tools + +LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 11 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.): -LLVM's tools to process coverage data and coverage maps have some version dependencies. If you encounter a version mismatch, try updating your LLVM tools. +* The LLVM tools may be installed (or installable) directly to your OS (such as via `apt-get`, for Linux). +* If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`. +* You can install compatible versions of these tools via `rustup`. + +The `rustup` option is guaranteed to install a compatible version of the LLVM tools, but they can be hard to find. We recommend [`cargo-bintools`], which installs Rust-specific wrappers around these and other LLVM tools, so you can invoke them via `cargo` commands! + +```shell +$ rustup component add llvm-tools-preview +$ cargo install cargo-binutils +$ cargo profdata -- --help # note the additional "--" preceeding the tool-specific arguments +``` -If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`. (Look for `llvm-profdata` and `llvm-cov`.) +## Creating coverage reports -Raw profiles have to be indexed before they can be used to generate coverage reports. This is done using [`llvm-profdata merge`] (which can combine multiple raw profiles and index them at the same time): +Raw profiles have to be indexed before they can be used to generate coverage reports. This is done using [`llvm-profdata merge`] (or `cargo cov -- merge`), which can combine multiple raw profiles and index them at the same time: ```shell $ llvm-profdata merge -sparse formatjson5.profraw -o formatjson5.profdata ``` -Finally, the `.profdata` file is used, in combination with the coverage map (from the program binary) to generate coverage reports using [`llvm-cov report`]--for a coverage summaries--and [`llvm-cov show`]--to see detailed coverage of lines and regions (character ranges), overlaid on the original source code. +Finally, the `.profdata` file is used, in combination with the coverage map (from the program binary) to generate coverage reports using [`llvm-cov report`] (or `cargo cov -- report`), for a coverage summaries; and [`llvm-cov show`] (or `cargo cov -- show`), to see detailed coverage of lines and regions (character ranges) overlaid on the original source code. These commands have several display and filtering options. For example: @@ -156,14 +168,77 @@ There are four statistics tracked in a coverage summary: Of these four statistics, function coverage is usually the least granular while region coverage is the most granular. The project-wide totals for each statistic are listed in the summary. +## Test coverage + +A typical use case for coverage analysis is test coverage. Rust's source-based coverage tools can both measure your tests' code coverage as percentage, and pinpoint functions and branches not tested. + +The following example (using the [`json5format`] crate, for demonstration purposes) show how to generate and analyze coverage results for all tests in a crate. + +Since `cargo test` both builds and runs the tests, we set both the additional `RUSTFLAGS`, to add the `-Zinstrument-coverage` flag, and `LLVM_PROFILE_FILE`, to set a custom filename for the raw profiling data generated during the test runs. Since there may be more than one test binary, apply `%m` in the filename pattern. This generates unique names for each test binary. (Otherwise, each executed test binary would overwrite the coverage results from the previous binary.) + +```shell +$ RUSTFLAGS="-Zinstrument-coverage" \ + LLVM_PROFILE_FILE="json5format-%m.profraw" \ + cargo test --tests +``` + +Make note of the test binary file paths, displayed after the word "`Running`" in the test output: + +```text + ... + Compiling json5format v0.1.3 ($HOME/json5format) + Finished test [unoptimized + debuginfo] target(s) in 14.60s + + Running target/debug/deps/json5format-fececd4653271682 +running 25 tests +... +test result: ok. 25 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + + Running target/debug/deps/lib-30768f9c53506dc5 +running 31 tests +... +test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +``` + +You should have one ore more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them: + +```shell +$ cargo profdata -- merge \ + -sparse json5format-*.profraw -o json5format.profdata +``` + +Then run the `cov` tool, with the `profdata` file and all test binaries: + +```shell +$ cargo cov -- report \ + --use-color --ignore-filename-regex='/.cargo/registry' \ + --instr-profile=json5format.profdata \ + target/debug/deps/lib-30768f9c53506dc5 \ + target/debug/deps/json5format-fececd4653271682 +$ cargo cov -- show \ + --use-color --ignore-filename-regex='/.cargo/registry' \ + --instr-profile=json5format.profdata \ + target/debug/deps/lib-30768f9c53506dc5 \ + target/debug/deps/json5format-fececd4653271682 \ + --show-instantiations --show-line-counts-or-regions \ + --Xdemangler=rustfilt | less -R +``` + +_Note the command line option `--ignore-filename-regex=/.cargo/registry`, which excludes the sources for dependencies from the coverage results._ + ## Other references -Rust's implementation and workflow for source-based code coverage is based on the same library and tools used to implement [source-based code coverage in Clang](https://clang.llvm.org/docs/SourceBasedCodeCoverage.html). (This document is partially based on the Clang guide.) +Rust's implementation and workflow for source-based code coverage is based on the same library and tools used to implement [source-based code coverage in Clang]. (This document is partially based on the Clang guide.) -[#34701]: https://github.com/rust-lang/rust/issues/34701 +[#79121]: https://github.com/rust-lang/rust/issues/79121 +[`-Zprofile`]: profile.md [`llvm.instrprof.increment`]: https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic [LLVM Code Coverage Mapping Format]: https://llvm.org/docs/CoverageMappingFormat.html [rustc-dev-guide-how-to-build-and-run]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html +[`rustfilt`]: https://crates.io/crates/rustfilt +[`json5format`]: https://crates.io/crates/json5format +[`cargo-bintools`]: https://crates.io/crates/cargo-bintools [`llvm-profdata merge`]: https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-merge [`llvm-cov report`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-report [`llvm-cov show`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-show +[source-based code coverage in Clang]: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html \ No newline at end of file diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index cabf5dccbfe91..2d902a9b6e08e 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -1,7 +1,6 @@ from sys import version_info import gdb -from gdb import lookup_type if version_info[0] >= 3: xrange = range @@ -213,7 +212,7 @@ def children_of_btree_map(map): def children_of_node(node_ptr, height): def cast_to_internal(node): internal_type_name = node.type.target().name.replace("LeafNode", "InternalNode", 1) - internal_type = lookup_type(internal_type_name) + internal_type = gdb.lookup_type(internal_type_name) return node.cast(internal_type.pointer()) if node_ptr.type.name.startswith("alloc::collections::btree::node::BoxedNode<"): @@ -233,8 +232,10 @@ def cast_to_internal(node): yield child if i < length: # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays. - key = keys[i]["value"]["value"] if keys.type.sizeof > 0 else "()" - val = vals[i]["value"]["value"] if vals.type.sizeof > 0 else "()" + key_type_size = keys.type.sizeof + val_type_size = vals.type.sizeof + key = keys[i]["value"]["value"] if key_type_size > 0 else gdb.parse_and_eval("()") + val = vals[i]["value"]["value"] if val_type_size > 0 else gdb.parse_and_eval("()") yield key, val if map["length"] > 0: diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d294d8f02a80f..8c344338de7a5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -162,9 +162,6 @@ impl Clean for CrateNum { .collect() }; - let get_span = - |attr: &ast::NestedMetaItem| Some(attr.meta_item()?.name_value_literal()?.span); - let as_keyword = |res: Res| { if let Res::Def(DefKind::Mod, def_id) = res { let attrs = cx.tcx.get_attrs(def_id).clean(cx); @@ -172,19 +169,7 @@ impl Clean for CrateNum { for attr in attrs.lists(sym::doc) { if attr.has_name(sym::keyword) { if let Some(v) = attr.value_str() { - let k = v.to_string(); - if !rustc_lexer::is_ident(&k) { - let sp = get_span(&attr).unwrap_or_else(|| attr.span()); - cx.tcx - .sess - .struct_span_err( - sp, - &format!("`{}` is not a valid identifier", v), - ) - .emit(); - } else { - keyword = Some(k); - } + keyword = Some(v.to_string()); break; } } @@ -1015,7 +1000,7 @@ impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { .iter() .map(|t| Argument { type_: t.clean(cx), - name: names.next().map_or(String::new(), |name| name.to_string()), + name: names.next().map_or_else(|| String::new(), |name| name.to_string()), }) .collect(), }, @@ -1989,16 +1974,13 @@ impl Clean for hir::BareFnTy<'_> { } } -impl Clean> for (&hir::Item<'_>, Option) { +impl Clean> for (&hir::Item<'_>, Option) { fn clean(&self, cx: &DocContext<'_>) -> Vec { use hir::ItemKind; let (item, renamed) = self; let def_id = cx.tcx.hir().local_def_id(item.hir_id).to_def_id(); - let mut name = match renamed { - Some(ident) => ident.name, - None => cx.tcx.hir().name(item.hir_id), - }; + let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id)); cx.with_param_env(def_id, || { let kind = match item.kind { ItemKind::Static(ty, mutability, body_id) => StaticItem(Static { @@ -2291,7 +2273,7 @@ impl Clean> for doctree::Import<'_> { } } -impl Clean for (&hir::ForeignItem<'_>, Option) { +impl Clean for (&hir::ForeignItem<'_>, Option) { fn clean(&self, cx: &DocContext<'_>) -> Item { let (item, renamed) = self; cx.with_param_env(cx.tcx.hir().local_def_id(item.hir_id).to_def_id(), || { @@ -2325,7 +2307,7 @@ impl Clean for (&hir::ForeignItem<'_>, Option) { Item::from_hir_id_and_parts( item.hir_id, - Some(renamed.unwrap_or(item.ident).name), + Some(renamed.unwrap_or(item.ident.name)), kind, cx, ) @@ -2333,10 +2315,10 @@ impl Clean for (&hir::ForeignItem<'_>, Option) { } } -impl Clean for (&hir::MacroDef<'_>, Option) { +impl Clean for (&hir::MacroDef<'_>, Option) { fn clean(&self, cx: &DocContext<'_>) -> Item { let (item, renamed) = self; - let name = renamed.unwrap_or(item.ident).name; + let name = renamed.unwrap_or(item.ident.name); let tts = item.ast.body.inner_tokens().trees().collect::>(); // Extract the spans of all matchers. They represent the "interface" of the macro. let matchers = tts.chunks(4).map(|arm| arm[0].span()).collect::>(); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 38d25d8d98e85..d4796b7ed66ca 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -337,6 +337,42 @@ crate enum ItemKind { } impl ItemKind { + /// Some items contain others such as structs (for their fields) and Enums + /// (for their variants). This method returns those contained items. + crate fn inner_items(&self) -> impl Iterator { + match self { + StructItem(s) => s.fields.iter(), + UnionItem(u) => u.fields.iter(), + VariantItem(Variant { kind: VariantKind::Struct(v) }) => v.fields.iter(), + EnumItem(e) => e.variants.iter(), + TraitItem(t) => t.items.iter(), + ImplItem(i) => i.items.iter(), + ModuleItem(m) => m.items.iter(), + ExternCrateItem(_, _) + | ImportItem(_) + | FunctionItem(_) + | TypedefItem(_, _) + | OpaqueTyItem(_) + | StaticItem(_) + | ConstantItem(_) + | TraitAliasItem(_) + | TyMethodItem(_) + | MethodItem(_, _) + | StructFieldItem(_) + | VariantItem(_) + | ForeignFunctionItem(_) + | ForeignStaticItem(_) + | ForeignTypeItem + | MacroItem(_) + | ProcMacroItem(_) + | PrimitiveItem(_) + | AssocConstItem(_, _) + | AssocTypeItem(_, _) + | StrippedItem(_) + | KeywordItem(_) => [].iter(), + } + } + crate fn is_type_alias(&self) -> bool { match *self { ItemKind::TypedefItem(_, _) | ItemKind::AssocTypeItem(_, _) => true, @@ -1613,6 +1649,11 @@ impl Path { crate fn last_name(&self) -> &str { self.segments.last().expect("segments were empty").name.as_str() } + + crate fn whole_name(&self) -> String { + String::from(if self.global { "::" } else { "" }) + + &self.segments.iter().map(|s| s.name.clone()).collect::>().join("::") + } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b63acdc114e89..9c693c290e7f4 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -13,7 +13,6 @@ use rustc_hir::{ }; use rustc_interface::interface; use rustc_middle::hir::map::Map; -use rustc_middle::middle::cstore::CrateStore; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_resolve as resolve; @@ -371,6 +370,7 @@ crate fn run_core( error_format, edition, describe_lints, + crate_name, ..Options::default() }; @@ -384,7 +384,6 @@ crate fn run_core( file_loader: None, diagnostic_output: DiagnosticOutput::Default, stderr: None, - crate_name, lint_caps, register_lints: None, override_queries: Some(|_sess, providers, _external_providers| { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a615701f253d3..37fe13c32ce74 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -74,6 +74,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { debugging_opts: config::DebuggingOptions { ..config::basic_debugging_options() }, edition: options.edition, target_triple: options.target.clone(), + crate_name: options.crate_name.clone(), ..config::Options::default() }; @@ -90,7 +91,6 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { file_loader: None, diagnostic_output: DiagnosticOutput::Default, stderr: None, - crate_name: options.crate_name.clone(), lint_caps, register_lints: None, override_queries: None, diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 3961870a1bfad..ee9a698185799 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -3,7 +3,7 @@ crate use self::StructType::*; use rustc_ast as ast; -use rustc_span::{self, symbol::Ident, Span, Symbol}; +use rustc_span::{self, Span, Symbol}; use rustc_hir as hir; @@ -16,9 +16,9 @@ crate struct Module<'hir> { crate mods: Vec>, crate id: hir::HirId, // (item, renamed) - crate items: Vec<(&'hir hir::Item<'hir>, Option)>, - crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option)>, - crate macros: Vec<(&'hir hir::MacroDef<'hir>, Option)>, + crate items: Vec<(&'hir hir::Item<'hir>, Option)>, + crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option)>, + crate macros: Vec<(&'hir hir::MacroDef<'hir>, Option)>, crate is_crate: bool, } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index c3153f2d4b6ff..e82bc540e95af 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -14,13 +14,13 @@ use crate::config::RenderInfo; use crate::fold::DocFolder; use crate::formats::item_type::ItemType; use crate::formats::Impl; +use crate::html::markdown::short_markdown_summary; use crate::html::render::cache::{extern_location, get_index_search_type, ExternalLocation}; use crate::html::render::IndexItem; -use crate::html::render::{plain_text_summary, shorten}; thread_local!(crate static CACHE_KEY: RefCell> = Default::default()); -/// This cache is used to store information about the `clean::Crate` being +/// This cache is used to store information about the [`clean::Crate`] being /// rendered in order to provide more useful documentation. This contains /// information like all implementors of a trait, all traits a type implements, /// documentation for all known traits, etc. @@ -313,7 +313,9 @@ impl DocFolder for Cache { ty: item.type_(), name: s.to_string(), path: path.join("::"), - desc: shorten(plain_text_summary(item.doc_value())), + desc: item + .doc_value() + .map_or_else(|| String::new(), short_markdown_summary), parent, parent_idx: None, search_type: get_index_search_type(&item), diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 8ce686c65502f..0e4c5410abe1e 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -17,8 +17,6 @@ //! // ... something using html //! ``` -#![allow(non_camel_case_types)] - use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_hir::HirId; @@ -1037,7 +1035,95 @@ impl MarkdownSummaryLine<'_> { } } +/// Renders a subset of Markdown in the first paragraph of the provided Markdown. +/// +/// - *Italics*, **bold**, and `inline code` styles **are** rendered. +/// - Headings and links are stripped (though the text *is* rendered). +/// - HTML, code blocks, and everything else are ignored. +/// +/// Returns a tuple of the rendered HTML string and whether the output was shortened +/// due to the provided `length_limit`. +fn markdown_summary_with_limit(md: &str, length_limit: usize) -> (String, bool) { + if md.is_empty() { + return (String::new(), false); + } + + let mut s = String::with_capacity(md.len() * 3 / 2); + let mut text_length = 0; + let mut stopped_early = false; + + fn push(s: &mut String, text_length: &mut usize, text: &str) { + s.push_str(text); + *text_length += text.len(); + }; + + 'outer: for event in Parser::new_ext(md, Options::ENABLE_STRIKETHROUGH) { + match &event { + Event::Text(text) => { + for word in text.split_inclusive(char::is_whitespace) { + if text_length + word.len() >= length_limit { + stopped_early = true; + break 'outer; + } + + push(&mut s, &mut text_length, word); + } + } + Event::Code(code) => { + if text_length + code.len() >= length_limit { + stopped_early = true; + break; + } + + s.push_str(""); + push(&mut s, &mut text_length, code); + s.push_str(""); + } + Event::Start(tag) => match tag { + Tag::Emphasis => s.push_str(""), + Tag::Strong => s.push_str(""), + Tag::CodeBlock(..) => break, + _ => {} + }, + Event::End(tag) => match tag { + Tag::Emphasis => s.push_str(""), + Tag::Strong => s.push_str(""), + Tag::Paragraph => break, + _ => {} + }, + Event::HardBreak | Event::SoftBreak => { + if text_length + 1 >= length_limit { + stopped_early = true; + break; + } + + push(&mut s, &mut text_length, " "); + } + _ => {} + } + } + + (s, stopped_early) +} + +/// Renders a shortened first paragraph of the given Markdown as a subset of Markdown, +/// making it suitable for contexts like the search index. +/// +/// Will shorten to 59 or 60 characters, including an ellipsis (…) if it was shortened. +/// +/// See [`markdown_summary_with_limit`] for details about what is rendered and what is not. +crate fn short_markdown_summary(markdown: &str) -> String { + let (mut s, was_shortened) = markdown_summary_with_limit(markdown, 59); + + if was_shortened { + s.push('…'); + } + + s +} + /// Renders the first paragraph of the provided markdown as plain text. +/// Useful for alt-text. /// /// - Headings, links, and formatting are stripped. /// - Inline code is rendered as-is, surrounded by backticks. diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 8e618733f078e..9807d8632c75d 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -1,4 +1,4 @@ -use super::plain_text_summary; +use super::{plain_text_summary, short_markdown_summary}; use super::{ErrorCodes, IdMap, Ignore, LangString, Markdown, MarkdownHtml}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use std::cell::RefCell; @@ -204,6 +204,33 @@ fn test_header_ids_multiple_blocks() { ); } +#[test] +fn test_short_markdown_summary() { + fn t(input: &str, expect: &str) { + let output = short_markdown_summary(input); + assert_eq!(output, expect, "original: {}", input); + } + + t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); + t("*italic*", "italic"); + t("**bold**", "bold"); + t("Multi-line\nsummary", "Multi-line summary"); + t("Hard-break \nsummary", "Hard-break summary"); + t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)"); + t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); + t("code `let x = i32;` ...", "code let x = i32; ..."); + t("type `Type<'static>` ...", "type Type<'static> ..."); + t("# top header", "top header"); + t("## header", "header"); + t("first paragraph\n\nsecond paragraph", "first paragraph"); + t("```\nfn main() {}\n```", ""); + t("
hello
", ""); + t( + "a *very*, **very** long first paragraph. it has lots of `inline code: Vec`. and it has a [link](https://www.rust-lang.org).\nthat was a soft line break! \nthat was a hard one\n\nsecond paragraph.", + "a very, very long first paragraph. it has lots of …", + ); +} + #[test] fn test_plain_text_summary() { fn t(input: &str, expect: &str) { @@ -224,6 +251,10 @@ fn test_plain_text_summary() { t("first paragraph\n\nsecond paragraph", "first paragraph"); t("```\nfn main() {}\n```", ""); t("
hello
", ""); + t( + "a *very*, **very** long first paragraph. it has lots of `inline code: Vec`. and it has a [link](https://www.rust-lang.org).\nthat was a soft line break! \nthat was a hard one\n\nsecond paragraph.", + "a very, very long first paragraph. it has lots of `inline code: Vec`. and it has a link. that was a soft line break! that was a hard one", + ); } #[test] diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 085ca01f58daa..97f764517faf6 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -9,7 +9,7 @@ use crate::clean::types::GetDefId; use crate::clean::{self, AttributesExt}; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::html::render::{plain_text_summary, shorten}; +use crate::html::markdown::short_markdown_summary; use crate::html::render::{Generic, IndexItem, IndexItemFunctionType, RenderType, TypeWithKind}; /// Indicates where an external crate can be found. @@ -78,7 +78,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { ty: item.type_(), name: item.name.clone().unwrap(), path: fqp[..fqp.len() - 1].join("::"), - desc: shorten(plain_text_summary(item.doc_value())), + desc: item.doc_value().map_or_else(|| String::new(), short_markdown_summary), parent: Some(did), parent_idx: None, search_type: get_index_search_type(&item), @@ -127,7 +127,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { let crate_doc = krate .module .as_ref() - .map(|module| shorten(plain_text_summary(module.doc_value()))) + .map(|module| module.doc_value().map_or_else(|| String::new(), short_markdown_summary)) .unwrap_or_default(); #[derive(Serialize)] diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index de620a35c80d7..901f00b21da9d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -76,7 +76,9 @@ use crate::html::format::fmt_impl_for_trait_page; use crate::html::format::Function; use crate::html::format::{href, print_default_space, print_generic_bounds, WhereClause}; use crate::html::format::{print_abi_with_space, Buffer, PrintWithSpace}; -use crate::html::markdown::{self, ErrorCodes, IdMap, Markdown, MarkdownHtml, MarkdownSummaryLine}; +use crate::html::markdown::{ + self, plain_text_summary, ErrorCodes, IdMap, Markdown, MarkdownHtml, MarkdownSummaryLine, +}; use crate::html::sources; use crate::html::{highlight, layout, static_files}; use cache::{build_index, ExternalLocation}; @@ -1604,9 +1606,10 @@ impl Context { Some(ref s) => s.to_string(), }; let short = short.to_string(); - map.entry(short) - .or_default() - .push((myname, Some(plain_text_summary(item.doc_value())))); + map.entry(short).or_default().push(( + myname, + Some(item.doc_value().map_or_else(|| String::new(), plain_text_summary)), + )); } if self.shared.sort_modules_alphabetically { @@ -1810,36 +1813,6 @@ fn full_path(cx: &Context, item: &clean::Item) -> String { s } -/// Renders the first paragraph of the given markdown as plain text, making it suitable for -/// contexts like alt-text or the search index. -/// -/// If no markdown is supplied, the empty string is returned. -/// -/// See [`markdown::plain_text_summary`] for further details. -#[inline] -crate fn plain_text_summary(s: Option<&str>) -> String { - s.map(markdown::plain_text_summary).unwrap_or_default() -} - -crate fn shorten(s: String) -> String { - if s.chars().count() > 60 { - let mut len = 0; - let mut ret = s - .split_whitespace() - .take_while(|p| { - // + 1 for the added character after the word. - len += p.chars().count() + 1; - len < 60 - }) - .collect::>() - .join(" "); - ret.push('…'); - ret - } else { - s - } -} - fn document(w: &mut Buffer, cx: &Context, item: &clean::Item, parent: Option<&clean::Item>) { if let Some(ref name) = item.name { info!("Documenting {}", name); diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 69984be5eb622..0884351a9fd80 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1611,7 +1611,7 @@ function defocusSearchBar() { item.displayPath + "" + name + "
"; }); output += "
" + "" + - "" + escape(item.desc) + + "" + item.desc + " 
"; @@ -2013,7 +2013,9 @@ function defocusSearchBar() { } var link = document.createElement("a"); link.href = rootPath + crates[i] + "/index.html"; - link.title = rawSearchIndex[crates[i]].doc; + // The summary in the search index has HTML, so we need to + // dynamically render it as plaintext. + link.title = convertHTMLToPlaintext(rawSearchIndex[crates[i]].doc); link.className = klass; link.textContent = crates[i]; @@ -2026,6 +2028,23 @@ function defocusSearchBar() { } }; + /** + * Convert HTML to plaintext: + * + * * Replace "foo" with "`foo`" + * * Strip all other HTML tags + * + * Used by the dynamic sidebar crate list renderer. + * + * @param {[string]} html [The HTML to convert] + * @return {[string]} [The resulting plaintext] + */ + function convertHTMLToPlaintext(html) { + var x = document.createElement("div"); + x.innerHTML = html.replace('', '`').replace('', '`'); + return x.innerText; + } + // delayed sidebar rendering. window.initSidebarItems = function(items) { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs new file mode 100644 index 0000000000000..afb8dfa676657 --- /dev/null +++ b/src/librustdoc/json/conversions.rs @@ -0,0 +1,599 @@ +//! These from impls are used to create the JSON types which get serialized. They're very close to +//! the `clean` types but with some fields removed or stringified to simplify the output and not +//! expose unstable compiler internals. + +use std::convert::From; + +use rustc_ast::ast; +use rustc_span::def_id::{DefId, CRATE_DEF_INDEX}; + +use crate::clean; +use crate::doctree; +use crate::formats::item_type::ItemType; +use crate::json::types::*; + +impl From for Option { + fn from(item: clean::Item) -> Self { + let item_type = ItemType::from(&item); + let clean::Item { + source, + name, + attrs, + kind, + visibility, + def_id, + stability: _, + const_stability: _, + deprecation, + } = item; + match kind { + clean::StrippedItem(_) => None, + _ => Some(Item { + id: def_id.into(), + crate_id: def_id.krate.as_u32(), + name, + source: source.into(), + visibility: visibility.into(), + docs: attrs.collapsed_doc_value().unwrap_or_default(), + links: attrs + .links + .into_iter() + .filter_map(|clean::ItemLink { link, did, .. }| { + did.map(|did| (link, did.into())) + }) + .collect(), + attrs: attrs + .other_attrs + .iter() + .map(rustc_ast_pretty::pprust::attribute_to_string) + .collect(), + deprecation: deprecation.map(Into::into), + kind: item_type.into(), + inner: kind.into(), + }), + } + } +} + +impl From for Option { + fn from(span: clean::Span) -> Self { + let clean::Span { loline, locol, hiline, hicol, .. } = span; + match span.filename { + rustc_span::FileName::Real(name) => Some(Span { + filename: match name { + rustc_span::RealFileName::Named(path) => path, + rustc_span::RealFileName::Devirtualized { local_path, virtual_name: _ } => { + local_path + } + }, + begin: (loline, locol), + end: (hiline, hicol), + }), + _ => None, + } + } +} + +impl From for Deprecation { + fn from(deprecation: clean::Deprecation) -> Self { + let clean::Deprecation { since, note, is_since_rustc_version: _ } = deprecation; + Deprecation { since, note } + } +} + +impl From for Visibility { + fn from(v: clean::Visibility) -> Self { + use clean::Visibility::*; + match v { + Public => Visibility::Public, + Inherited => Visibility::Default, + Restricted(did, _) if did.index == CRATE_DEF_INDEX => Visibility::Crate, + Restricted(did, path) => Visibility::Restricted { + parent: did.into(), + path: path.to_string_no_crate_verbose(), + }, + } + } +} + +impl From for GenericArgs { + fn from(args: clean::GenericArgs) -> Self { + use clean::GenericArgs::*; + match args { + AngleBracketed { args, bindings } => GenericArgs::AngleBracketed { + args: args.into_iter().map(Into::into).collect(), + bindings: bindings.into_iter().map(Into::into).collect(), + }, + Parenthesized { inputs, output } => GenericArgs::Parenthesized { + inputs: inputs.into_iter().map(Into::into).collect(), + output: output.map(Into::into), + }, + } + } +} + +impl From for GenericArg { + fn from(arg: clean::GenericArg) -> Self { + use clean::GenericArg::*; + match arg { + Lifetime(l) => GenericArg::Lifetime(l.0), + Type(t) => GenericArg::Type(t.into()), + Const(c) => GenericArg::Const(c.into()), + } + } +} + +impl From for Constant { + fn from(constant: clean::Constant) -> Self { + let clean::Constant { type_, expr, value, is_literal } = constant; + Constant { type_: type_.into(), expr, value, is_literal } + } +} + +impl From for TypeBinding { + fn from(binding: clean::TypeBinding) -> Self { + TypeBinding { name: binding.name, binding: binding.kind.into() } + } +} + +impl From for TypeBindingKind { + fn from(kind: clean::TypeBindingKind) -> Self { + use clean::TypeBindingKind::*; + match kind { + Equality { ty } => TypeBindingKind::Equality(ty.into()), + Constraint { bounds } => { + TypeBindingKind::Constraint(bounds.into_iter().map(Into::into).collect()) + } + } + } +} + +impl From for Id { + fn from(did: DefId) -> Self { + Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index))) + } +} + +impl From for ItemEnum { + fn from(item: clean::ItemKind) -> Self { + use clean::ItemKind::*; + match item { + ModuleItem(m) => ItemEnum::ModuleItem(m.into()), + ExternCrateItem(c, a) => ItemEnum::ExternCrateItem { name: c, rename: a }, + ImportItem(i) => ItemEnum::ImportItem(i.into()), + StructItem(s) => ItemEnum::StructItem(s.into()), + UnionItem(u) => ItemEnum::StructItem(u.into()), + StructFieldItem(f) => ItemEnum::StructFieldItem(f.into()), + EnumItem(e) => ItemEnum::EnumItem(e.into()), + VariantItem(v) => ItemEnum::VariantItem(v.into()), + FunctionItem(f) => ItemEnum::FunctionItem(f.into()), + ForeignFunctionItem(f) => ItemEnum::FunctionItem(f.into()), + TraitItem(t) => ItemEnum::TraitItem(t.into()), + TraitAliasItem(t) => ItemEnum::TraitAliasItem(t.into()), + MethodItem(m, _) => ItemEnum::MethodItem(m.into()), + TyMethodItem(m) => ItemEnum::MethodItem(m.into()), + ImplItem(i) => ItemEnum::ImplItem(i.into()), + StaticItem(s) => ItemEnum::StaticItem(s.into()), + ForeignStaticItem(s) => ItemEnum::StaticItem(s.into()), + ForeignTypeItem => ItemEnum::ForeignTypeItem, + TypedefItem(t, _) => ItemEnum::TypedefItem(t.into()), + OpaqueTyItem(t) => ItemEnum::OpaqueTyItem(t.into()), + ConstantItem(c) => ItemEnum::ConstantItem(c.into()), + MacroItem(m) => ItemEnum::MacroItem(m.source), + ProcMacroItem(m) => ItemEnum::ProcMacroItem(m.into()), + AssocConstItem(t, s) => ItemEnum::AssocConstItem { type_: t.into(), default: s }, + AssocTypeItem(g, t) => ItemEnum::AssocTypeItem { + bounds: g.into_iter().map(Into::into).collect(), + default: t.map(Into::into), + }, + StrippedItem(inner) => (*inner).into(), + PrimitiveItem(_) | KeywordItem(_) => { + panic!("{:?} is not supported for JSON output", item) + } + } + } +} + +impl From for Module { + fn from(module: clean::Module) -> Self { + Module { is_crate: module.is_crate, items: ids(module.items) } + } +} + +impl From for Struct { + fn from(struct_: clean::Struct) -> Self { + let clean::Struct { struct_type, generics, fields, fields_stripped } = struct_; + Struct { + struct_type: struct_type.into(), + generics: generics.into(), + fields_stripped, + fields: ids(fields), + impls: Vec::new(), // Added in JsonRenderer::item + } + } +} + +impl From for Struct { + fn from(struct_: clean::Union) -> Self { + let clean::Union { struct_type, generics, fields, fields_stripped } = struct_; + Struct { + struct_type: struct_type.into(), + generics: generics.into(), + fields_stripped, + fields: ids(fields), + impls: Vec::new(), // Added in JsonRenderer::item + } + } +} + +impl From for StructType { + fn from(struct_type: doctree::StructType) -> Self { + use doctree::StructType::*; + match struct_type { + Plain => StructType::Plain, + Tuple => StructType::Tuple, + Unit => StructType::Unit, + } + } +} + +fn stringify_header(header: &rustc_hir::FnHeader) -> String { + let mut s = String::from(header.unsafety.prefix_str()); + if header.asyncness == rustc_hir::IsAsync::Async { + s.push_str("async ") + } + if header.constness == rustc_hir::Constness::Const { + s.push_str("const ") + } + s +} + +impl From for Function { + fn from(function: clean::Function) -> Self { + let clean::Function { decl, generics, header, all_types: _, ret_types: _ } = function; + Function { + decl: decl.into(), + generics: generics.into(), + header: stringify_header(&header), + abi: header.abi.to_string(), + } + } +} + +impl From for Generics { + fn from(generics: clean::Generics) -> Self { + Generics { + params: generics.params.into_iter().map(Into::into).collect(), + where_predicates: generics.where_predicates.into_iter().map(Into::into).collect(), + } + } +} + +impl From for GenericParamDef { + fn from(generic_param: clean::GenericParamDef) -> Self { + GenericParamDef { name: generic_param.name, kind: generic_param.kind.into() } + } +} + +impl From for GenericParamDefKind { + fn from(kind: clean::GenericParamDefKind) -> Self { + use clean::GenericParamDefKind::*; + match kind { + Lifetime => GenericParamDefKind::Lifetime, + Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type { + bounds: bounds.into_iter().map(Into::into).collect(), + default: default.map(Into::into), + }, + Const { did: _, ty } => GenericParamDefKind::Const(ty.into()), + } + } +} + +impl From for WherePredicate { + fn from(predicate: clean::WherePredicate) -> Self { + use clean::WherePredicate::*; + match predicate { + BoundPredicate { ty, bounds } => WherePredicate::BoundPredicate { + ty: ty.into(), + bounds: bounds.into_iter().map(Into::into).collect(), + }, + RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate { + lifetime: lifetime.0, + bounds: bounds.into_iter().map(Into::into).collect(), + }, + EqPredicate { lhs, rhs } => { + WherePredicate::EqPredicate { lhs: lhs.into(), rhs: rhs.into() } + } + } + } +} + +impl From for GenericBound { + fn from(bound: clean::GenericBound) -> Self { + use clean::GenericBound::*; + match bound { + TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => { + GenericBound::TraitBound { + trait_: trait_.into(), + generic_params: generic_params.into_iter().map(Into::into).collect(), + modifier: modifier.into(), + } + } + Outlives(lifetime) => GenericBound::Outlives(lifetime.0), + } + } +} + +impl From for TraitBoundModifier { + fn from(modifier: rustc_hir::TraitBoundModifier) -> Self { + use rustc_hir::TraitBoundModifier::*; + match modifier { + None => TraitBoundModifier::None, + Maybe => TraitBoundModifier::Maybe, + MaybeConst => TraitBoundModifier::MaybeConst, + } + } +} + +impl From for Type { + fn from(ty: clean::Type) -> Self { + use clean::Type::*; + match ty { + ResolvedPath { path, param_names, did, is_generic: _ } => Type::ResolvedPath { + name: path.whole_name(), + id: did.into(), + args: path.segments.last().map(|args| Box::new(args.clone().args.into())), + param_names: param_names + .map(|v| v.into_iter().map(Into::into).collect()) + .unwrap_or_default(), + }, + Generic(s) => Type::Generic(s), + Primitive(p) => Type::Primitive(p.as_str().to_string()), + BareFunction(f) => Type::FunctionPointer(Box::new((*f).into())), + Tuple(t) => Type::Tuple(t.into_iter().map(Into::into).collect()), + Slice(t) => Type::Slice(Box::new((*t).into())), + Array(t, s) => Type::Array { type_: Box::new((*t).into()), len: s }, + ImplTrait(g) => Type::ImplTrait(g.into_iter().map(Into::into).collect()), + Never => Type::Never, + Infer => Type::Infer, + RawPointer(mutability, type_) => Type::RawPointer { + mutable: mutability == ast::Mutability::Mut, + type_: Box::new((*type_).into()), + }, + BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef { + lifetime: lifetime.map(|l| l.0), + mutable: mutability == ast::Mutability::Mut, + type_: Box::new((*type_).into()), + }, + QPath { name, self_type, trait_ } => Type::QualifiedPath { + name, + self_type: Box::new((*self_type).into()), + trait_: Box::new((*trait_).into()), + }, + } + } +} + +impl From for FunctionPointer { + fn from(bare_decl: clean::BareFunctionDecl) -> Self { + let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl; + FunctionPointer { + is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, + generic_params: generic_params.into_iter().map(Into::into).collect(), + decl: decl.into(), + abi: abi.to_string(), + } + } +} + +impl From for FnDecl { + fn from(decl: clean::FnDecl) -> Self { + let clean::FnDecl { inputs, output, c_variadic, attrs: _ } = decl; + FnDecl { + inputs: inputs.values.into_iter().map(|arg| (arg.name, arg.type_.into())).collect(), + output: match output { + clean::FnRetTy::Return(t) => Some(t.into()), + clean::FnRetTy::DefaultReturn => None, + }, + c_variadic, + } + } +} + +impl From for Trait { + fn from(trait_: clean::Trait) -> Self { + let clean::Trait { unsafety, items, generics, bounds, is_spotlight: _, is_auto } = trait_; + Trait { + is_auto, + is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, + items: ids(items), + generics: generics.into(), + bounds: bounds.into_iter().map(Into::into).collect(), + implementors: Vec::new(), // Added in JsonRenderer::item + } + } +} + +impl From for Impl { + fn from(impl_: clean::Impl) -> Self { + let clean::Impl { + unsafety, + generics, + provided_trait_methods, + trait_, + for_, + items, + polarity, + synthetic, + blanket_impl, + } = impl_; + Impl { + is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, + generics: generics.into(), + provided_trait_methods: provided_trait_methods.into_iter().collect(), + trait_: trait_.map(Into::into), + for_: for_.into(), + items: ids(items), + negative: polarity == Some(clean::ImplPolarity::Negative), + synthetic, + blanket_impl: blanket_impl.map(Into::into), + } + } +} + +impl From for Method { + fn from(function: clean::Function) -> Self { + let clean::Function { header, decl, generics, all_types: _, ret_types: _ } = function; + Method { + decl: decl.into(), + generics: generics.into(), + header: stringify_header(&header), + has_body: true, + } + } +} + +impl From for Enum { + fn from(enum_: clean::Enum) -> Self { + let clean::Enum { variants, generics, variants_stripped } = enum_; + Enum { + generics: generics.into(), + variants_stripped, + variants: ids(variants), + impls: Vec::new(), // Added in JsonRenderer::item + } + } +} + +impl From for Struct { + fn from(struct_: clean::VariantStruct) -> Self { + let clean::VariantStruct { struct_type, fields, fields_stripped } = struct_; + Struct { + struct_type: struct_type.into(), + generics: Default::default(), + fields_stripped, + fields: ids(fields), + impls: Vec::new(), + } + } +} + +impl From for Variant { + fn from(variant: clean::Variant) -> Self { + use clean::VariantKind::*; + match variant.kind { + CLike => Variant::Plain, + Tuple(t) => Variant::Tuple(t.into_iter().map(Into::into).collect()), + Struct(s) => Variant::Struct(ids(s.fields)), + } + } +} + +impl From for Import { + fn from(import: clean::Import) -> Self { + use clean::ImportKind::*; + match import.kind { + Simple(s) => Import { + span: import.source.path.whole_name(), + name: s, + id: import.source.did.map(Into::into), + glob: false, + }, + Glob => Import { + span: import.source.path.whole_name(), + name: import.source.path.last_name().to_string(), + id: import.source.did.map(Into::into), + glob: true, + }, + } + } +} + +impl From for ProcMacro { + fn from(mac: clean::ProcMacro) -> Self { + ProcMacro { kind: mac.kind.into(), helpers: mac.helpers } + } +} + +impl From for MacroKind { + fn from(kind: rustc_span::hygiene::MacroKind) -> Self { + use rustc_span::hygiene::MacroKind::*; + match kind { + Bang => MacroKind::Bang, + Attr => MacroKind::Attr, + Derive => MacroKind::Derive, + } + } +} + +impl From for Typedef { + fn from(typedef: clean::Typedef) -> Self { + let clean::Typedef { type_, generics, item_type: _ } = typedef; + Typedef { type_: type_.into(), generics: generics.into() } + } +} + +impl From for OpaqueTy { + fn from(opaque: clean::OpaqueTy) -> Self { + OpaqueTy { + bounds: opaque.bounds.into_iter().map(Into::into).collect(), + generics: opaque.generics.into(), + } + } +} + +impl From for Static { + fn from(stat: clean::Static) -> Self { + Static { + type_: stat.type_.into(), + mutable: stat.mutability == ast::Mutability::Mut, + expr: stat.expr, + } + } +} + +impl From for TraitAlias { + fn from(alias: clean::TraitAlias) -> Self { + TraitAlias { + generics: alias.generics.into(), + params: alias.bounds.into_iter().map(Into::into).collect(), + } + } +} + +impl From for ItemKind { + fn from(kind: ItemType) -> Self { + use ItemType::*; + match kind { + Module => ItemKind::Module, + ExternCrate => ItemKind::ExternCrate, + Import => ItemKind::Import, + Struct => ItemKind::Struct, + Union => ItemKind::Union, + Enum => ItemKind::Enum, + Function => ItemKind::Function, + Typedef => ItemKind::Typedef, + OpaqueTy => ItemKind::OpaqueTy, + Static => ItemKind::Static, + Constant => ItemKind::Constant, + Trait => ItemKind::Trait, + Impl => ItemKind::Impl, + TyMethod | Method => ItemKind::Method, + StructField => ItemKind::StructField, + Variant => ItemKind::Variant, + Macro => ItemKind::Macro, + Primitive => ItemKind::Primitive, + AssocConst => ItemKind::AssocConst, + AssocType => ItemKind::AssocType, + ForeignType => ItemKind::ForeignType, + Keyword => ItemKind::Keyword, + TraitAlias => ItemKind::TraitAlias, + ProcAttribute => ItemKind::ProcAttribute, + ProcDerive => ItemKind::ProcDerive, + } + } +} + +fn ids(items: impl IntoIterator) -> Vec { + items.into_iter().filter(|x| !x.is_stripped()).map(|i| i.def_id.into()).collect() +} diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 5eb1f7b1f7780..c080ad21c0f33 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -1,47 +1,238 @@ +//! Rustdoc's JSON backend +//! +//! This module contains the logic for rendering a crate as JSON rather than the normal static HTML +//! output. See [the RFC](https://github.com/rust-lang/rfcs/pull/2963) and the [`types`] module +//! docs for usage and details. + +mod conversions; +pub mod types; + +use std::cell::RefCell; +use std::fs::File; +use std::path::PathBuf; +use std::rc::Rc; + +use rustc_data_structures::fx::FxHashMap; +use rustc_span::edition::Edition; + use crate::clean; use crate::config::{RenderInfo, RenderOptions}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::FormatRenderer; - -use rustc_span::edition::Edition; +use crate::html::render::cache::ExternalLocation; #[derive(Clone)] -crate struct JsonRenderer {} +crate struct JsonRenderer { + /// A mapping of IDs that contains all local items for this crate which gets output as a top + /// level field of the JSON blob. + index: Rc>>, + /// The directory where the blob will be written to. + out_path: PathBuf, +} + +impl JsonRenderer { + fn get_trait_implementors( + &mut self, + id: rustc_span::def_id::DefId, + cache: &Cache, + ) -> Vec { + cache + .implementors + .get(&id) + .map(|implementors| { + implementors + .iter() + .map(|i| { + let item = &i.impl_item; + self.item(item.clone(), cache).unwrap(); + item.def_id.into() + }) + .collect() + }) + .unwrap_or_default() + } + + fn get_impls(&mut self, id: rustc_span::def_id::DefId, cache: &Cache) -> Vec { + cache + .impls + .get(&id) + .map(|impls| { + impls + .iter() + .filter_map(|i| { + let item = &i.impl_item; + if item.def_id.is_local() { + self.item(item.clone(), cache).unwrap(); + Some(item.def_id.into()) + } else { + None + } + }) + .collect() + }) + .unwrap_or_default() + } + + fn get_trait_items(&mut self, cache: &Cache) -> Vec<(types::Id, types::Item)> { + cache + .traits + .iter() + .filter_map(|(&id, trait_item)| { + // only need to synthesize items for external traits + if !id.is_local() { + trait_item.items.clone().into_iter().for_each(|i| self.item(i, cache).unwrap()); + Some(( + id.into(), + types::Item { + id: id.into(), + crate_id: id.krate.as_u32(), + name: cache + .paths + .get(&id) + .unwrap_or_else(|| { + cache + .external_paths + .get(&id) + .expect("Trait should either be in local or external paths") + }) + .0 + .last() + .map(Clone::clone), + visibility: types::Visibility::Public, + kind: types::ItemKind::Trait, + inner: types::ItemEnum::TraitItem(trait_item.clone().into()), + source: None, + docs: Default::default(), + links: Default::default(), + attrs: Default::default(), + deprecation: Default::default(), + }, + )) + } else { + None + } + }) + .collect() + } +} impl FormatRenderer for JsonRenderer { fn init( - _krate: clean::Crate, - _options: RenderOptions, + krate: clean::Crate, + options: RenderOptions, _render_info: RenderInfo, _edition: Edition, _cache: &mut Cache, ) -> Result<(Self, clean::Crate), Error> { - unimplemented!() + debug!("Initializing json renderer"); + Ok(( + JsonRenderer { + index: Rc::new(RefCell::new(FxHashMap::default())), + out_path: options.output, + }, + krate, + )) } - fn item(&mut self, _item: clean::Item, _cache: &Cache) -> Result<(), Error> { - unimplemented!() + /// Inserts an item into the index. This should be used rather than directly calling insert on + /// the hashmap because certain items (traits and types) need to have their mappings for trait + /// implementations filled out before they're inserted. + fn item(&mut self, item: clean::Item, cache: &Cache) -> Result<(), Error> { + // Flatten items that recursively store other items + item.kind.inner_items().for_each(|i| self.item(i.clone(), cache).unwrap()); + + let id = item.def_id; + if let Some(mut new_item) = item.into(): Option { + if let types::ItemEnum::TraitItem(ref mut t) = new_item.inner { + t.implementors = self.get_trait_implementors(id, cache) + } else if let types::ItemEnum::StructItem(ref mut s) = new_item.inner { + s.impls = self.get_impls(id, cache) + } else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner { + e.impls = self.get_impls(id, cache) + } + self.index.borrow_mut().insert(id.into(), new_item); + } + + Ok(()) } fn mod_item_in( &mut self, - _item: &clean::Item, - _item_name: &str, - _cache: &Cache, + item: &clean::Item, + _module_name: &str, + cache: &Cache, ) -> Result<(), Error> { - unimplemented!() + use clean::types::ItemKind::*; + if let ModuleItem(m) = &item.kind { + for item in &m.items { + match &item.kind { + // These don't have names so they don't get added to the output by default + ImportItem(_) => self.item(item.clone(), cache).unwrap(), + ExternCrateItem(_, _) => self.item(item.clone(), cache).unwrap(), + ImplItem(i) => { + i.items.iter().for_each(|i| self.item(i.clone(), cache).unwrap()) + } + _ => {} + } + } + } + self.item(item.clone(), cache).unwrap(); + Ok(()) } fn mod_item_out(&mut self, _item_name: &str) -> Result<(), Error> { - unimplemented!() + Ok(()) } - fn after_krate(&mut self, _krate: &clean::Crate, _cache: &Cache) -> Result<(), Error> { - unimplemented!() + fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error> { + debug!("Done with crate"); + let mut index = (*self.index).clone().into_inner(); + index.extend(self.get_trait_items(cache)); + let output = types::Crate { + root: types::Id(String::from("0:0")), + crate_version: krate.version.clone(), + includes_private: cache.document_private, + index, + paths: cache + .paths + .clone() + .into_iter() + .chain(cache.external_paths.clone().into_iter()) + .map(|(k, (path, kind))| { + ( + k.into(), + types::ItemSummary { crate_id: k.krate.as_u32(), path, kind: kind.into() }, + ) + }) + .collect(), + external_crates: cache + .extern_locations + .iter() + .map(|(k, v)| { + ( + k.as_u32(), + types::ExternalCrate { + name: v.0.clone(), + html_root_url: match &v.2 { + ExternalLocation::Remote(s) => Some(s.clone()), + _ => None, + }, + }, + ) + }) + .collect(), + format_version: 1, + }; + let mut p = self.out_path.clone(); + p.push(output.index.get(&output.root).unwrap().name.clone().unwrap()); + p.set_extension("json"); + let file = File::create(&p).map_err(|error| Error { error: error.to_string(), file: p })?; + serde_json::ser::to_writer(&file, &output).unwrap(); + Ok(()) } fn after_run(&mut self, _diag: &rustc_errors::Handler) -> Result<(), Error> { - unimplemented!() + Ok(()) } } diff --git a/src/librustdoc/json/types.rs b/src/librustdoc/json/types.rs new file mode 100644 index 0000000000000..10bf2a2acc5b9 --- /dev/null +++ b/src/librustdoc/json/types.rs @@ -0,0 +1,490 @@ +//! Rustdoc's JSON output interface +//! +//! These types are the public API exposed through the `--output-format json` flag. The [`Crate`] +//! struct is the root of the JSON blob and all other items are contained within. + +use std::path::PathBuf; + +use rustc_data_structures::fx::FxHashMap; +use serde::{Deserialize, Serialize}; + +/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information +/// about the language items in the local crate, as well as info about external items to allow +/// tools to find or link to them. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Crate { + /// The id of the root [`Module`] item of the local crate. + pub root: Id, + /// The version string given to `--crate-version`, if any. + pub crate_version: Option, + /// Whether or not the output includes private items. + pub includes_private: bool, + /// A collection of all items in the local crate as well as some external traits and their + /// items that are referenced locally. + pub index: FxHashMap, + /// Maps IDs to fully qualified paths and other info helpful for generating links. + pub paths: FxHashMap, + /// Maps `crate_id` of items to a crate name and html_root_url if it exists. + pub external_crates: FxHashMap, + /// A single version number to be used in the future when making backwards incompatible changes + /// to the JSON output. + pub format_version: u32, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ExternalCrate { + pub name: String, + pub html_root_url: Option, +} + +/// For external (not defined in the local crate) items, you don't get the same level of +/// information. This struct should contain enough to generate a link/reference to the item in +/// question, or can be used by a tool that takes the json output of multiple crates to find +/// the actual item definition with all the relevant info. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ItemSummary { + /// Can be used to look up the name and html_root_url of the crate this item came from in the + /// `external_crates` map. + pub crate_id: u32, + /// The list of path components for the fully qualified path of this item (e.g. + /// `["std", "io", "lazy", "Lazy"]` for `std::io::lazy::Lazy`). + pub path: Vec, + /// Whether this item is a struct, trait, macro, etc. + pub kind: ItemKind, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Item { + /// The unique identifier of this item. Can be used to find this item in various mappings. + pub id: Id, + /// This can be used as a key to the `external_crates` map of [`Crate`] to see which crate + /// this item came from. + pub crate_id: u32, + /// Some items such as impls don't have names. + pub name: Option, + /// The source location of this item (absent if it came from a macro expansion or inline + /// assembly). + pub source: Option, + /// By default all documented items are public, but you can tell rustdoc to output private items + /// so this field is needed to differentiate. + pub visibility: Visibility, + /// The full markdown docstring of this item. + pub docs: String, + /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs + pub links: FxHashMap, + /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`) + pub attrs: Vec, + pub deprecation: Option, + pub kind: ItemKind, + pub inner: ItemEnum, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Span { + /// The path to the source file for this span relative to the path `rustdoc` was invoked with. + pub filename: PathBuf, + /// Zero indexed Line and Column of the first character of the `Span` + pub begin: (usize, usize), + /// Zero indexed Line and Column of the last character of the `Span` + pub end: (usize, usize), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Deprecation { + pub since: Option, + pub note: Option, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Visibility { + Public, + /// For the most part items are private by default. The exceptions are associated items of + /// public traits and variants of public enums. + Default, + Crate, + /// For `pub(in path)` visibility. `parent` is the module it's restricted to and `path` is how + /// that module was referenced (like `"super::super"` or `"crate::foo::bar"`). + Restricted { + parent: Id, + path: String, + }, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GenericArgs { + /// <'a, 32, B: Copy, C = u32> + AngleBracketed { args: Vec, bindings: Vec }, + /// Fn(A, B) -> C + Parenthesized { inputs: Vec, output: Option }, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GenericArg { + Lifetime(String), + Type(Type), + Const(Constant), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Constant { + #[serde(rename = "type")] + pub type_: Type, + pub expr: String, + pub value: Option, + pub is_literal: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TypeBinding { + pub name: String, + pub binding: TypeBindingKind, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum TypeBindingKind { + Equality(Type), + Constraint(Vec), +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct Id(pub String); + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum ItemKind { + Module, + ExternCrate, + Import, + Struct, + StructField, + Union, + Enum, + Variant, + Function, + Typedef, + OpaqueTy, + Constant, + Trait, + TraitAlias, + Method, + Impl, + Static, + ForeignType, + Macro, + ProcAttribute, + ProcDerive, + AssocConst, + AssocType, + Primitive, + Keyword, +} + +#[serde(untagged)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum ItemEnum { + ModuleItem(Module), + ExternCrateItem { + name: String, + rename: Option, + }, + ImportItem(Import), + + StructItem(Struct), + StructFieldItem(Type), + EnumItem(Enum), + VariantItem(Variant), + + FunctionItem(Function), + + TraitItem(Trait), + TraitAliasItem(TraitAlias), + MethodItem(Method), + ImplItem(Impl), + + TypedefItem(Typedef), + OpaqueTyItem(OpaqueTy), + ConstantItem(Constant), + + StaticItem(Static), + + /// `type`s from an extern block + ForeignTypeItem, + + /// Declarative macro_rules! macro + MacroItem(String), + ProcMacroItem(ProcMacro), + + AssocConstItem { + #[serde(rename = "type")] + type_: Type, + /// e.g. `const X: usize = 5;` + default: Option, + }, + AssocTypeItem { + bounds: Vec, + /// e.g. `type X = usize;` + default: Option, + }, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Module { + pub is_crate: bool, + pub items: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Struct { + pub struct_type: StructType, + pub generics: Generics, + pub fields_stripped: bool, + pub fields: Vec, + pub impls: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Enum { + pub generics: Generics, + pub variants_stripped: bool, + pub variants: Vec, + pub impls: Vec, +} + +#[serde(rename_all = "snake_case")] +#[serde(tag = "variant_kind", content = "variant_inner")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Variant { + Plain, + Tuple(Vec), + Struct(Vec), +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum StructType { + Plain, + Tuple, + Unit, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Function { + pub decl: FnDecl, + pub generics: Generics, + pub header: String, + pub abi: String, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Method { + pub decl: FnDecl, + pub generics: Generics, + pub header: String, + pub has_body: bool, +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct Generics { + pub params: Vec, + pub where_predicates: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct GenericParamDef { + pub name: String, + pub kind: GenericParamDefKind, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GenericParamDefKind { + Lifetime, + Type { bounds: Vec, default: Option }, + Const(Type), +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum WherePredicate { + BoundPredicate { ty: Type, bounds: Vec }, + RegionPredicate { lifetime: String, bounds: Vec }, + EqPredicate { lhs: Type, rhs: Type }, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GenericBound { + TraitBound { + #[serde(rename = "trait")] + trait_: Type, + /// Used for HRTBs + generic_params: Vec, + modifier: TraitBoundModifier, + }, + Outlives(String), +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum TraitBoundModifier { + None, + Maybe, + MaybeConst, +} + +#[serde(rename_all = "snake_case")] +#[serde(tag = "kind", content = "inner")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Type { + /// Structs, enums, and traits + ResolvedPath { + name: String, + id: Id, + args: Option>, + param_names: Vec, + }, + /// Parameterized types + Generic(String), + /// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples + Primitive(String), + /// `extern "ABI" fn` + FunctionPointer(Box), + /// `(String, u32, Box)` + Tuple(Vec), + /// `[u32]` + Slice(Box), + /// [u32; 15] + Array { + #[serde(rename = "type")] + type_: Box, + len: String, + }, + /// `impl TraitA + TraitB + ...` + ImplTrait(Vec), + /// `!` + Never, + /// `_` + Infer, + /// `*mut u32`, `*u8`, etc. + RawPointer { + mutable: bool, + #[serde(rename = "type")] + type_: Box, + }, + /// `&'a mut String`, `&str`, etc. + BorrowedRef { + lifetime: Option, + mutable: bool, + #[serde(rename = "type")] + type_: Box, + }, + /// `::Name` or associated types like `T::Item` where `T: Iterator` + QualifiedPath { + name: String, + self_type: Box, + #[serde(rename = "trait")] + trait_: Box, + }, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct FunctionPointer { + pub is_unsafe: bool, + pub generic_params: Vec, + pub decl: FnDecl, + pub abi: String, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct FnDecl { + pub inputs: Vec<(String, Type)>, + pub output: Option, + pub c_variadic: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Trait { + pub is_auto: bool, + pub is_unsafe: bool, + pub items: Vec, + pub generics: Generics, + pub bounds: Vec, + pub implementors: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TraitAlias { + pub generics: Generics, + pub params: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Impl { + pub is_unsafe: bool, + pub generics: Generics, + pub provided_trait_methods: Vec, + #[serde(rename = "trait")] + pub trait_: Option, + #[serde(rename = "for")] + pub for_: Type, + pub items: Vec, + pub negative: bool, + pub synthetic: bool, + pub blanket_impl: Option, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Import { + /// The full path being imported. + pub span: String, + /// May be different from the last segment of `source` when renaming imports: + /// `use source as name;` + pub name: String, + /// The ID of the item being imported. + pub id: Option, // FIXME is this actually ever None? + /// Whether this import uses a glob: `use source::*;` + pub glob: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ProcMacro { + pub kind: MacroKind, + pub helpers: Vec, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum MacroKind { + /// A bang macro `foo!()`. + Bang, + /// An attribute macro `#[foo]`. + Attr, + /// A derive macro `#[derive(Foo)]` + Derive, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Typedef { + #[serde(rename = "type")] + pub type_: Type, + pub generics: Generics, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct OpaqueTy { + pub bounds: Vec, + pub generics: Generics, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Static { + #[serde(rename = "type")] + pub type_: Type, + pub mutable: bool, + pub expr: String, +} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 751f230105392..26bf4b569ff4b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -14,6 +14,8 @@ #![feature(crate_visibility_modifier)] #![feature(never_type)] #![feature(once_cell)] +#![feature(type_ascription)] +#![feature(split_inclusive)] #![recursion_limit = "256"] #[macro_use] diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3dcc0f240a3f8..551c086a8d4e3 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -847,12 +847,17 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly let self_name = self_id.and_then(|self_id| { + use ty::TyKind; if matches!(self.cx.tcx.def_kind(self_id), DefKind::Impl) { - // using `ty.to_string()` directly has issues with shortening paths + // using `ty.to_string()` (or any variant) has issues with raw idents let ty = self.cx.tcx.type_of(self_id); - let name = ty::print::with_crate_prefix(|| ty.to_string()); - debug!("using type_of(): {}", name); - Some(name) + let name = match ty.kind() { + TyKind::Adt(def, _) => Some(self.cx.tcx.item_name(def.did).to_string()), + other if other.is_primitive() => Some(ty.to_string()), + _ => None, + }; + debug!("using type_of(): {:?}", name); + name } else { let name = self.cx.tcx.opt_item_name(self_id).map(|sym| sym.to_string()); debug!("using item_name(): {:?}", name); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4028293076df9..f9cb1d586b102 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -10,7 +10,7 @@ use rustc_hir::Node; use rustc_middle::middle::privacy::AccessLevel; use rustc_middle::ty::TyCtxt; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{self, Span}; use std::mem; @@ -116,7 +116,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { &mut self, id: hir::HirId, res: Res, - renamed: Option, + renamed: Option, glob: bool, om: &mut Module<'tcx>, please_inline: bool, @@ -226,11 +226,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { fn visit_item( &mut self, item: &'tcx hir::Item<'_>, - renamed: Option, + renamed: Option, om: &mut Module<'tcx>, ) { debug!("visiting item {:?}", item); - let ident = renamed.unwrap_or(item.ident); + let name = renamed.unwrap_or(item.ident.name); if item.vis.node.is_pub() { let def_id = self.cx.tcx.hir().local_def_id(item.hir_id); @@ -266,7 +266,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } _ => false, }); - let ident = if is_glob { None } else { Some(ident) }; + let ident = if is_glob { None } else { Some(name) }; if self.maybe_inline_local( item.hir_id, path.res, @@ -280,7 +280,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } om.imports.push(Import { - name: ident.name, + name, id: item.hir_id, vis: &item.vis, attrs: &item.attrs, @@ -296,7 +296,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { &item.vis, item.hir_id, m, - Some(ident.name), + Some(name), )); } hir::ItemKind::Fn(..) @@ -312,7 +312,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::ItemKind::Const(..) => { // Underscore constants do not correspond to a nameable item and // so are never useful in documentation. - if ident.name != kw::Underscore { + if name != kw::Underscore { om.items.push((item, renamed)); } } @@ -329,7 +329,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { fn visit_foreign_item( &mut self, item: &'tcx hir::ForeignItem<'_>, - renamed: Option, + renamed: Option, om: &mut Module<'tcx>, ) { // If inlining we only want to include public functions. diff --git a/src/test/codegen/return-value-in-reg.rs b/src/test/codegen/arg-return-value-in-reg.rs similarity index 74% rename from src/test/codegen/return-value-in-reg.rs rename to src/test/codegen/arg-return-value-in-reg.rs index 4bc0136c5e325..a69291d47821a 100644 --- a/src/test/codegen/return-value-in-reg.rs +++ b/src/test/codegen/arg-return-value-in-reg.rs @@ -1,4 +1,4 @@ -//! This test checks that types of up to 128 bits are returned by-value instead of via out-pointer. +//! Check that types of up to 128 bits are passed and returned by-value instead of via pointer. // compile-flags: -C no-prepopulate-passes -O // only-x86_64 @@ -11,7 +11,7 @@ pub struct S { c: u32, } -// CHECK: define i128 @modify(%S* noalias nocapture dereferenceable(16) %s) +// CHECK: define i128 @modify(i128{{( %0)?}}) #[no_mangle] pub fn modify(s: S) -> S { S { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c } diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs index afea01e9a2d03..f282fd237054c 100644 --- a/src/test/codegen/union-abi.rs +++ b/src/test/codegen/union-abi.rs @@ -63,11 +63,16 @@ pub union UnionU128{a:u128} #[no_mangle] pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} } +pub union UnionU128x2{a:(u128, u128)} +// CHECK: define void @test_UnionU128x2(i128 %_1.0, i128 %_1.1) +#[no_mangle] +pub fn test_UnionU128x2(_: UnionU128x2) { loop {} } + #[repr(C)] -pub union CUnionU128{a:u128} -// CHECK: define void @test_CUnionU128(%CUnionU128* {{.*}} %_1) +pub union CUnionU128x2{a:(u128, u128)} +// CHECK: define void @test_CUnionU128x2(%CUnionU128x2* {{.*}} %_1) #[no_mangle] -pub fn test_CUnionU128(_: CUnionU128) { loop {} } +pub fn test_CUnionU128x2(_: CUnionU128x2) { loop {} } pub union UnionBool { b:bool } // CHECK: define zeroext i1 @test_UnionBool(i8 %b) diff --git a/src/test/incremental/cyclic-trait-hierarchy.rs b/src/test/incremental/cyclic-trait-hierarchy.rs index b502e7207d561..03bb5eea765cc 100644 --- a/src/test/incremental/cyclic-trait-hierarchy.rs +++ b/src/test/incremental/cyclic-trait-hierarchy.rs @@ -3,11 +3,11 @@ // revisions: rpass1 cfail2 #[cfg(rpass1)] -pub trait T2 {} +pub trait T2 { } #[cfg(cfail2)] -pub trait T2: T1 {} -//[cfail2]~^ ERROR cycle detected when computing the super predicates of `T2` +pub trait T2: T1 { } +//[cfail2]~^ ERROR cycle detected when computing the supertraits of `T2` -pub trait T1: T2 {} +pub trait T1: T2 { } -fn main() {} +fn main() { } diff --git a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir index 7e0ca3dea4b71..0c7b64cb97f8f 100644 --- a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir @@ -41,44 +41,36 @@ fn main() -> () { StorageLive(_5); // scope 3 at $DIR/basic_assignment.rs:19:9: 19:15 StorageLive(_6); // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20 _6 = move _4; // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20 - replace(_5 <- move _6) -> [return: bb1, unwind: bb5]; // scope 4 at $DIR/basic_assignment.rs:23:5: 23:11 + replace(_5 <- move _6) -> [return: bb1, unwind: bb4]; // scope 4 at $DIR/basic_assignment.rs:23:5: 23:11 } bb1: { - drop(_6) -> [return: bb2, unwind: bb6]; // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 - } - - bb2: { StorageDead(_6); // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 _0 = const (); // scope 0 at $DIR/basic_assignment.rs:10:11: 24:2 - drop(_5) -> [return: bb3, unwind: bb7]; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 + drop(_5) -> [return: bb2, unwind: bb5]; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb3: { + bb2: { StorageDead(_5); // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 - drop(_4) -> [return: bb4, unwind: bb8]; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 + drop(_4) -> [return: bb3, unwind: bb6]; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb4: { + bb3: { StorageDead(_4); // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 StorageDead(_2); // scope 1 at $DIR/basic_assignment.rs:24:1: 24:2 StorageDead(_1); // scope 0 at $DIR/basic_assignment.rs:24:1: 24:2 return; // scope 0 at $DIR/basic_assignment.rs:24:2: 24:2 } - bb5 (cleanup): { - drop(_6) -> bb6; // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 - } - - bb6 (cleanup): { - drop(_5) -> bb7; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 + bb4 (cleanup): { + drop(_5) -> bb5; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb7 (cleanup): { - drop(_4) -> bb8; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 + bb5 (cleanup): { + drop(_4) -> bb6; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb8 (cleanup): { + bb6 (cleanup): { resume; // scope 0 at $DIR/basic_assignment.rs:10:1: 24:2 } } diff --git a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir index cfbd3a58637c0..20ea7b026bc6e 100644 --- a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir @@ -14,7 +14,7 @@ fn main() -> () { StorageLive(_1); // scope 0 at $DIR/box_expr.rs:7:9: 7:10 StorageLive(_2); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 _2 = Box(S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - (*_2) = S::new() -> [return: bb1, unwind: bb7]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 + (*_2) = S::new() -> [return: bb1, unwind: bb5]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 // mir::Constant // + span: $DIR/box_expr.rs:7:17: 7:23 // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar()) } @@ -22,45 +22,37 @@ fn main() -> () { bb1: { _1 = move _2; // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - drop(_2) -> bb2; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 - } - - bb2: { StorageDead(_2); // scope 0 at $DIR/box_expr.rs:7:24: 7:25 StorageLive(_3); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 StorageLive(_4); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 _4 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 - _3 = std::mem::drop::>(move _4) -> [return: bb3, unwind: bb5]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + _3 = std::mem::drop::>(move _4) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 // mir::Constant // + span: $DIR/box_expr.rs:8:5: 8:9 // + literal: Const { ty: fn(std::boxed::Box) {std::mem::drop::>}, val: Value(Scalar()) } } - bb3: { + bb2: { StorageDead(_4); // scope 1 at $DIR/box_expr.rs:8:11: 8:12 StorageDead(_3); // scope 1 at $DIR/box_expr.rs:8:12: 8:13 _0 = const (); // scope 0 at $DIR/box_expr.rs:6:11: 9:2 - drop(_1) -> bb4; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + drop(_1) -> bb3; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } - bb4: { + bb3: { StorageDead(_1); // scope 0 at $DIR/box_expr.rs:9:1: 9:2 return; // scope 0 at $DIR/box_expr.rs:9:2: 9:2 } - bb5 (cleanup): { - drop(_4) -> bb6; // scope 1 at $DIR/box_expr.rs:8:11: 8:12 - } - - bb6 (cleanup): { - drop(_1) -> bb8; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + bb4 (cleanup): { + drop(_1) -> bb6; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } - bb7 (cleanup): { - drop(_2) -> bb8; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + bb5 (cleanup): { + drop(_2) -> bb6; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 } - bb8 (cleanup): { + bb6 (cleanup): { resume; // scope 0 at $DIR/box_expr.rs:6:1: 9:2 } } diff --git a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff index 80b7e7ecddab9..0d06c4960b363 100644 --- a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff +++ b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff @@ -15,7 +15,7 @@ } bb1: { - _0 = const (); // scope 0 at $DIR/control-flow-simplification.rs:12:5: 14:6 + _0 = const (); // scope 0 at $DIR/control-flow-simplification.rs:14:6: 14:6 StorageDead(_1); // scope 0 at $DIR/control-flow-simplification.rs:15:1: 15:2 return; // scope 0 at $DIR/control-flow-simplification.rs:15:2: 15:2 } diff --git a/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir b/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir index 4898f9deb0cae..c2f75e5daeeb2 100644 --- a/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir +++ b/src/test/mir-opt/const_prop/control_flow_simplification.hello.PreCodegen.before.mir @@ -4,7 +4,7 @@ fn hello() -> () { let mut _0: (); // return place in scope 0 at $DIR/control-flow-simplification.rs:11:14: 11:14 bb0: { - _0 = const (); // scope 0 at $DIR/control-flow-simplification.rs:12:5: 14:6 + _0 = const (); // scope 0 at $DIR/control-flow-simplification.rs:14:6: 14:6 return; // scope 0 at $DIR/control-flow-simplification.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot b/src/test/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot index efc06bdea57a6..124f2d8b97a00 100644 --- a/src/test/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot +++ b/src/test/mir-opt/coverage_graphviz.bar.InstrumentCoverage.0.dot @@ -2,5 +2,5 @@ digraph Cov_0_4 { graph [fontname="Courier, monospace"]; node [fontname="Courier, monospace"]; edge [fontname="Courier, monospace"]; - bcb0__Cov_0_4 [shape="none", label=<
bcb0
Counter(bcb0) at 19:5-20:2
19:5-19:9: @0[0]: _0 = const true
20:2-20:2: @0.Return: return
bb0: Return
>]; + bcb0__Cov_0_4 [shape="none", label=<
bcb0
Counter(bcb0) at 18:1-20:2
19:5-19:9: @0[0]: _0 = const true
20:2-20:2: @0.Return: return
bb0: Return
>]; } diff --git a/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot b/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot index 5ddd112fe62e6..d88193da4fb19 100644 --- a/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot +++ b/src/test/mir-opt/coverage_graphviz.main.InstrumentCoverage.0.dot @@ -2,9 +2,9 @@ digraph Cov_0_3 { graph [fontname="Courier, monospace"]; node [fontname="Courier, monospace"]; edge [fontname="Courier, monospace"]; - bcb2__Cov_0_3 [shape="none", label=<
bcb2
Expression(bcb0 - bcb1) at 14:6-14:6
14:6-14:6: @4.Goto: goto -> bb0
bb4: Goto
>]; + bcb2__Cov_0_3 [shape="none", label=<
bcb2
Expression(bcb0 - bcb1) at 13:10-13:10
13:10-13:10: @4[0]: _1 = const ()
bb4: Goto
>]; bcb1__Cov_0_3 [shape="none", label=<
bcb1
Counter(bcb1) at 12:13-12:18
12:13-12:18: @5[0]: _0 = const ()
Expression(bcb1 + 0) at 15:2-15:2
15:2-15:2: @5.Return: return
bb3: FalseEdge
bb5: Return
>]; - bcb0__Cov_0_3 [shape="none", label=<
bcb0
Counter(bcb0) at 11:12-11:17
11:12-11:17: @1.Call: _2 = bar() -> [return: bb2, unwind: bb6]
11:12-11:17: @2[0]: FakeRead(ForMatchedPlace, _2)
bb0: FalseUnwind
bb1: Call
bb2: SwitchInt
>]; + bcb0__Cov_0_3 [shape="none", label=<
bcb0
Counter(bcb0) at 9:1-11:17
11:12-11:17: @1.Call: _2 = bar() -> [return: bb2, unwind: bb6]
11:12-11:17: @2[0]: FakeRead(ForMatchedPlace, _2)
bb0: FalseUnwind
bb1: Call
bb2: SwitchInt
>]; bcb2__Cov_0_3 -> bcb0__Cov_0_3 [label=<>]; bcb0__Cov_0_3 -> bcb2__Cov_0_3 [label=]; bcb0__Cov_0_3 -> bcb1__Cov_0_3 [label=]; diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff index 07994eb3c1661..22737381c71ae 100644 --- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff @@ -5,18 +5,19 @@ let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12 let _1: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 -+ let mut _7: (); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _8: (); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ let mut _9: (); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + scope 1 (inlined call_twice:: ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22 + debug f => _2; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + let _3: !; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _5: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _6: !; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 ++ let mut _7: !; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + scope 2 { + debug a => _3; // in scope 2 at $DIR/inline-diverging.rs:22:5: 22:22 + scope 3 { -+ debug b => _6; // in scope 3 at $DIR/inline-diverging.rs:22:5: 22:22 ++ debug b => _7; // in scope 3 at $DIR/inline-diverging.rs:22:5: 22:22 + } + scope 6 (inlined ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:22:5: 22:22 + scope 7 (inlined sleep) { // at $DIR/inline-diverging.rs:22:5: 22:22 @@ -40,12 +41,12 @@ - // mir::Constant // + span: $DIR/inline-diverging.rs:22:16: 22:21 // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar()) } -+ StorageLive(_6); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ StorageLive(_7); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + StorageLive(_3); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 -+ StorageLive(_7); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 -+ _7 = const (); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 ++ StorageLive(_8); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 ++ _8 = const (); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:22:5: 22:22 } diff --git a/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff index dac9ec3b443d7..a8b523d06dfc7 100644 --- a/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff +++ b/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff @@ -57,7 +57,7 @@ } bb1: { - _7 = const (); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + _7 = const (); // scope 4 at $DIR/inst_combine_deref.rs:60:23: 60:23 StorageDead(_8); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23 StorageDead(_7); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23 _0 = const (); // scope 0 at $DIR/inst_combine_deref.rs:54:24: 61:2 diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff index 5048359e5c654..112a698309276 100644 --- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff @@ -6,7 +6,7 @@ bb0: { _0 = const true; // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9 -+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:20:5 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 ++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:19:1 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 return; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 } } diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index c67d0e2ffe656..83dee7efa6db4 100644 --- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -21,7 +21,7 @@ bb2: { FakeRead(ForMatchedPlace, _2); // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 -+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:12:12 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 ++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 switchInt(_2) -> [false: bb4, otherwise: bb3]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 } @@ -30,9 +30,9 @@ } bb4: { - _1 = const (); // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 + _1 = const (); // scope 0 at /the/src/instrument_coverage.rs:14:10: 14:10 StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6 -+ Coverage::Expression(4294967295) = 1 - 2 for /the/src/instrument_coverage.rs:15:6 - 15:7; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 ++ Coverage::Expression(4294967295) = 1 - 2 for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 goto -> bb0; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } diff --git a/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir index 0929ba9d8a266..30036e4034af6 100644 --- a/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir @@ -35,7 +35,7 @@ fn main() -> () { } bb4: { - _3 = const (); // scope 1 at $DIR/issue-38669.rs:7:9: 9:10 + _3 = const (); // scope 1 at $DIR/issue-38669.rs:9:10: 9:10 StorageDead(_4); // scope 1 at $DIR/issue-38669.rs:9:9: 9:10 StorageDead(_3); // scope 1 at $DIR/issue-38669.rs:9:9: 9:10 _1 = const true; // scope 1 at $DIR/issue-38669.rs:10:9: 10:28 diff --git a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir index 7113c42b9c77f..bbbd2bcf128b1 100644 --- a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir @@ -6,21 +6,18 @@ fn main() -> () { let mut _2: S; // in scope 0 at $DIR/issue-41110.rs:8:13: 8:14 let mut _3: S; // in scope 0 at $DIR/issue-41110.rs:8:21: 8:27 let mut _4: S; // in scope 0 at $DIR/issue-41110.rs:8:21: 8:22 - let mut _5: bool; // in scope 0 at $DIR/issue-41110.rs:8:27: 8:28 scope 1 { debug x => _1; // in scope 1 at $DIR/issue-41110.rs:8:9: 8:10 } bb0: { - _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:9: 8:10 StorageLive(_1); // scope 0 at $DIR/issue-41110.rs:8:9: 8:10 StorageLive(_2); // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 - _5 = const true; // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 _2 = S; // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 StorageLive(_3); // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 StorageLive(_4); // scope 0 at $DIR/issue-41110.rs:8:21: 8:22 _4 = S; // scope 0 at $DIR/issue-41110.rs:8:21: 8:22 - _3 = S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 + _3 = S::id(move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 // mir::Constant // + span: $DIR/issue-41110.rs:8:23: 8:25 // + literal: Const { ty: fn(S) -> S {S::id}, val: Value(Scalar()) } @@ -28,8 +25,7 @@ fn main() -> () { bb1: { StorageDead(_4); // scope 0 at $DIR/issue-41110.rs:8:26: 8:27 - _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 - _1 = S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 + _1 = S::other(move _2, move _3) -> bb2; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 // mir::Constant // + span: $DIR/issue-41110.rs:8:15: 8:20 // + literal: Const { ty: fn(S, S) {S::other}, val: Value(Scalar()) } @@ -37,7 +33,6 @@ fn main() -> () { bb2: { StorageDead(_3); // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 StorageDead(_2); // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 _0 = const (); // scope 0 at $DIR/issue-41110.rs:7:11: 9:2 StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:9:1: 9:2 @@ -45,26 +40,10 @@ fn main() -> () { } bb3 (cleanup): { - goto -> bb5; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 + drop(_2) -> bb4; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 } bb4 (cleanup): { - goto -> bb5; // scope 0 at $DIR/issue-41110.rs:8:26: 8:27 - } - - bb5 (cleanup): { - goto -> bb8; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - } - - bb6 (cleanup): { resume; // scope 0 at $DIR/issue-41110.rs:7:1: 9:2 } - - bb7 (cleanup): { - drop(_2) -> bb6; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - } - - bb8 (cleanup): { - switchInt(_5) -> [false: bb6, otherwise: bb7]; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - } } diff --git a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir index c4e852ca3212a..b0c7260f0f4dc 100644 --- a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir @@ -25,7 +25,7 @@ fn test() -> () { StorageLive(_3); // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 StorageLive(_4); // scope 2 at $DIR/issue-41110.rs:17:10: 17:11 _4 = move _2; // scope 2 at $DIR/issue-41110.rs:17:10: 17:11 - _3 = std::mem::drop::(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 + _3 = std::mem::drop::(move _4) -> [return: bb1, unwind: bb5]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 // mir::Constant // + span: $DIR/issue-41110.rs:17:5: 17:9 // + literal: Const { ty: fn(S) {std::mem::drop::}, val: Value(Scalar()) } @@ -37,65 +37,53 @@ fn test() -> () { StorageLive(_5); // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 _6 = const false; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 _5 = move _1; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 - goto -> bb12; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 + goto -> bb9; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } bb2: { - goto -> bb3; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 - } - - bb3: { StorageDead(_5); // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 _0 = const (); // scope 0 at $DIR/issue-41110.rs:14:15: 19:2 - drop(_2) -> [return: bb4, unwind: bb9]; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 + drop(_2) -> [return: bb3, unwind: bb6]; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 } - bb4: { + bb3: { StorageDead(_2); // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 - goto -> bb5; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + goto -> bb4; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } - bb5: { + bb4: { _6 = const false; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 return; // scope 0 at $DIR/issue-41110.rs:19:2: 19:2 } - bb6 (cleanup): { - goto -> bb8; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 - } - - bb7 (cleanup): { - goto -> bb8; // scope 2 at $DIR/issue-41110.rs:17:11: 17:12 - } - - bb8 (cleanup): { - goto -> bb9; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 + bb5 (cleanup): { + goto -> bb6; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 } - bb9 (cleanup): { - goto -> bb14; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + bb6 (cleanup): { + goto -> bb11; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } - bb10 (cleanup): { + bb7 (cleanup): { resume; // scope 0 at $DIR/issue-41110.rs:14:1: 19:2 } - bb11 (cleanup): { + bb8 (cleanup): { _2 = move _5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 - goto -> bb6; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 + goto -> bb5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } - bb12: { + bb9: { _2 = move _5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 goto -> bb2; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } - bb13 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + bb10 (cleanup): { + drop(_1) -> bb7; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } - bb14 (cleanup): { - switchInt(_6) -> [false: bb10, otherwise: bb13]; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + bb11 (cleanup): { + switchInt(_6) -> [false: bb7, otherwise: bb10]; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } } diff --git a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir index d7b4e073cea4c..5011c2adfa581 100644 --- a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir @@ -26,7 +26,7 @@ fn main() -> () { _8 = const false; // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 StorageLive(_1); // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 StorageLive(_2); // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 - _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 + _2 = cond() -> [return: bb1, unwind: bb9]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 // mir::Constant // + span: $DIR/issue-41888.rs:8:8: 8:12 // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar()) } @@ -37,8 +37,8 @@ fn main() -> () { } bb2: { - _0 = const (); // scope 1 at $DIR/issue-41888.rs:8:5: 14:6 - goto -> bb8; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6 + _0 = const (); // scope 1 at $DIR/issue-41888.rs:14:6: 14:6 + goto -> bb7; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6 } bb3: { @@ -47,38 +47,34 @@ fn main() -> () { _4 = K; // scope 1 at $DIR/issue-41888.rs:9:18: 9:19 _3 = E::F(move _4); // scope 1 at $DIR/issue-41888.rs:9:13: 9:20 StorageDead(_4); // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 - goto -> bb14; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + goto -> bb12; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } bb4: { - goto -> bb5; // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 - } - - bb5: { StorageDead(_3); // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 _5 = discriminant(_1); // scope 1 at $DIR/issue-41888.rs:10:16: 10:24 - switchInt(move _5) -> [0_isize: bb7, otherwise: bb6]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24 + switchInt(move _5) -> [0_isize: bb6, otherwise: bb5]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24 } - bb6: { - _0 = const (); // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 - goto -> bb8; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 + bb5: { + _0 = const (); // scope 1 at $DIR/issue-41888.rs:13:10: 13:10 + goto -> bb7; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 } - bb7: { + bb6: { StorageLive(_6); // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 _9 = const false; // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 _6 = move ((_1 as F).0: K); // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 _0 = const (); // scope 2 at $DIR/issue-41888.rs:10:29: 13:10 StorageDead(_6); // scope 1 at $DIR/issue-41888.rs:13:9: 13:10 - goto -> bb8; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 + goto -> bb7; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 } - bb8: { - goto -> bb20; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb7: { + goto -> bb18; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb9: { + bb8: { _7 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 _8 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 _9 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 @@ -87,27 +83,23 @@ fn main() -> () { return; // scope 0 at $DIR/issue-41888.rs:15:2: 15:2 } - bb10 (cleanup): { - goto -> bb11; // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 - } - - bb11 (cleanup): { - goto -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb9 (cleanup): { + goto -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb12 (cleanup): { + bb10 (cleanup): { resume; // scope 0 at $DIR/issue-41888.rs:6:1: 15:2 } - bb13 (cleanup): { + bb11 (cleanup): { _7 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _8 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _9 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _1 = move _3; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 - goto -> bb10; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + goto -> bb9; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } - bb14: { + bb12: { _7 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _8 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _9 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 @@ -115,38 +107,38 @@ fn main() -> () { goto -> bb4; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } - bb15: { + bb13: { _7 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 - goto -> bb9; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + goto -> bb8; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb16 (cleanup): { - goto -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb14 (cleanup): { + goto -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb17: { - drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb15: { + drop(_1) -> [return: bb13, unwind: bb10]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb18 (cleanup): { - drop(_1) -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb16 (cleanup): { + drop(_1) -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb19: { + bb17: { _10 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 - switchInt(move _10) -> [0_isize: bb15, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + switchInt(move _10) -> [0_isize: bb13, otherwise: bb15]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb20: { - switchInt(_7) -> [false: bb15, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb18: { + switchInt(_7) -> [false: bb13, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb21 (cleanup): { + bb19 (cleanup): { _11 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 - switchInt(move _11) -> [0_isize: bb16, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + switchInt(move _11) -> [0_isize: bb14, otherwise: bb16]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb22 (cleanup): { - switchInt(_7) -> [false: bb12, otherwise: bb21]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb20 (cleanup): { + switchInt(_7) -> [false: bb10, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } } diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index c1421f20a0ba2..f74cdd7191927 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -30,7 +30,7 @@ fn test() -> Option> { StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 _4 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = as Try>::into_result(move _4) -> [return: bb1, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _3 = as Try>::into_result(move _4) -> [return: bb1, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(std::option::Option) -> std::result::Result< as std::ops::Try>::Ok, as std::ops::Try>::Error> { as std::ops::Try>::into_result}, val: Value(Scalar()) } @@ -48,7 +48,11 @@ fn test() -> Option> { (*_2) = _10; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20 StorageDead(_10); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 _1 = move _2; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - drop(_2) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 + StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + goto -> bb8; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } bb3: { @@ -61,7 +65,7 @@ fn test() -> Option> { StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageLive(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 _9 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = >::from(move _9) -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = >::from(move _9) -> [return: bb5, unwind: bb10]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:19: 9:20 // + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {>::from}, val: Value(Scalar()) } @@ -69,7 +73,7 @@ fn test() -> Option> { bb5: { StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = > as Try>::from_error(move _8) -> [return: bb6, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 + _0 = > as Try>::from_error(move _8) -> [return: bb6, unwind: bb10]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(> as std::ops::Try>::Error) -> std::option::Option> {> as std::ops::Try>::from_error}, val: Value(Scalar()) } @@ -78,41 +82,29 @@ fn test() -> Option> { bb6: { StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - drop(_2) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_2) -> [return: bb7, unwind: bb9]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb7: { - StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 - _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 - drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - } - - bb8: { - StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 - } - - bb9: { StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + goto -> bb8; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb10: { + bb8: { return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb11 (cleanup): { - drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + bb9 (cleanup): { + drop(_0) -> bb11; // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 } - bb12 (cleanup): { - drop(_2) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + bb10 (cleanup): { + drop(_2) -> bb11; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } - bb13 (cleanup): { + bb11 (cleanup): { resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir index 05def56e65eb5..56df50c089318 100644 --- a/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir +++ b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir @@ -25,7 +25,7 @@ fn main() -> () { } bb2: { - _1 = const (); // scope 0 at $DIR/loop_test.rs:10:5: 12:6 + _1 = const (); // scope 0 at $DIR/loop_test.rs:12:6: 12:6 StorageDead(_2); // scope 0 at $DIR/loop_test.rs:12:5: 12:6 StorageDead(_1); // scope 0 at $DIR/loop_test.rs:12:5: 12:6 StorageLive(_4); // scope 0 at $DIR/loop_test.rs:13:5: 16:6 diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff index ba963e3fe920b..d0b1a96b9aef7 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff @@ -34,7 +34,7 @@ } bb4: { - _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 + _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:9:6: 9:6 goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff index ba963e3fe920b..d0b1a96b9aef7 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff @@ -34,7 +34,7 @@ } bb4: { - _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 + _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:9:6: 9:6 goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 } diff --git a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir index bbb433dbe25c7..2f95931d2b2a1 100644 --- a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir @@ -28,7 +28,7 @@ fn main() -> () { bb1: { StorageDead(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:33: 9:34 - _1 = std::mem::drop::(move _2) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 + _1 = std::mem::drop::(move _2) -> bb2; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:5: 9:19 // + literal: Const { ty: fn(std::string::String) {std::mem::drop::}, val: Value(Scalar()) } @@ -41,12 +41,4 @@ fn main() -> () { _0 = const (); // scope 0 at $DIR/no-spurious-drop-after-call.rs:8:11: 10:2 return; // scope 0 at $DIR/no-spurious-drop-after-call.rs:10:2: 10:2 } - - bb3 (cleanup): { - drop(_2) -> bb4; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:34: 9:35 - } - - bb4 (cleanup): { - resume; // scope 0 at $DIR/no-spurious-drop-after-call.rs:8:1: 10:2 - } } diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff index 62743057048fb..5588877aec950 100644 --- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff +++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff @@ -33,7 +33,7 @@ - - bb4: { + bb2: { - _1 = const (); // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10 + _1 = const (); // scope 0 at $DIR/simplify_cfg.rs:9:10: 9:10 StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:10:5: 10:6 goto -> bb0; // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6 } diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff index 9a6afc58c4e9d..e62935225d805 100644 --- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff +++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff @@ -40,7 +40,7 @@ - bb5: { + bb4: { - _1 = const (); // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10 + _1 = const (); // scope 0 at $DIR/simplify_cfg.rs:9:10: 9:10 - goto -> bb9; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10 + StorageDead(_2); // scope 0 at $DIR/simplify_cfg.rs:10:5: 10:6 + goto -> bb0; // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6 diff --git a/src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff b/src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff index aeb319a4904bf..bf3caf505eda1 100644 --- a/src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff +++ b/src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff @@ -14,7 +14,7 @@ } bb1: { - _0 = const (); // scope 0 at $DIR/simplify_if.rs:6:5: 8:6 + _0 = const (); // scope 0 at $DIR/simplify_if.rs:8:6: 8:6 goto -> bb4; // scope 0 at $DIR/simplify_if.rs:6:5: 8:6 } diff --git a/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff index 45808962bb564..9f7507a5cadb2 100644 --- a/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff @@ -30,7 +30,7 @@ } bb1: { - _0 = const (); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6 + _0 = const (); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:8:6: 8:6 goto -> bb7; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6 } @@ -51,7 +51,7 @@ } bb4: { - _0 = const (); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10 + _0 = const (); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:7:10: 7:10 goto -> bb6; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10 } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir index d18f6308ded84..9bca5d24605fb 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir @@ -22,62 +22,38 @@ fn move_out_by_subslice() -> () { _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 - } - - bb1: { StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 - } - - bb2: { StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27 - drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - } - - bb3: { StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - } - - bb4: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 FakeRead(ForLet, _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _6 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2 - drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_6) -> [return: bb1, unwind: bb3]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb5: { + bb1: { StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 - drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb6: { + bb2: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2 } - bb7 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 - } - - bb8 (cleanup): { - drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - } - - bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + bb3 (cleanup): { + drop(_1) -> bb4; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb10 (cleanup): { + bb4 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir index eda8e5fd3afe7..c9004416f2ec1 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir @@ -22,62 +22,38 @@ fn move_out_from_end() -> () { _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 - } - - bb1: { StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 - } - - bb2: { StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27 - drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - } - - bb3: { StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - } - - bb4: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 FakeRead(ForLet, _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _6 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2 - drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_6) -> [return: bb1, unwind: bb3]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb5: { + bb1: { StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 - drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb6: { + bb2: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2 } - bb7 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 - } - - bb8 (cleanup): { - drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - } - - bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + bb3 (cleanup): { + drop(_1) -> bb4; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb10 (cleanup): { + bb4 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2 } } diff --git a/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff index 37ff5c6ee3bbd..6f44de1e4a4f5 100644 --- a/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff @@ -32,7 +32,7 @@ } bb2: { - _0 = const (); // scope 0 at $DIR/unreachable.rs:9:5: 19:6 + _0 = const (); // scope 0 at $DIR/unreachable.rs:19:6: 19:6 StorageDead(_1); // scope 0 at $DIR/unreachable.rs:20:1: 20:2 return; // scope 0 at $DIR/unreachable.rs:20:2: 20:2 - } diff --git a/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff index 5caacf84ca657..9bca06a3e2b28 100644 --- a/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff @@ -34,7 +34,7 @@ } bb2: { - _0 = const (); // scope 0 at $DIR/unreachable_asm.rs:11:5: 23:6 + _0 = const (); // scope 0 at $DIR/unreachable_asm.rs:23:6: 23:6 StorageDead(_1); // scope 0 at $DIR/unreachable_asm.rs:24:1: 24:2 return; // scope 0 at $DIR/unreachable_asm.rs:24:2: 24:2 } diff --git a/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff index 07ed81b35f53d..cbc24eab0f568 100644 --- a/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff @@ -37,7 +37,7 @@ } bb2: { - _0 = const (); // scope 0 at $DIR/unreachable_asm_2.rs:11:5: 25:6 + _0 = const (); // scope 0 at $DIR/unreachable_asm_2.rs:25:6: 25:6 StorageDead(_1); // scope 0 at $DIR/unreachable_asm_2.rs:26:1: 26:2 return; // scope 0 at $DIR/unreachable_asm_2.rs:26:2: 26:2 } diff --git a/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff index c809483d8c2c4..fd8286f1c4f39 100644 --- a/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff @@ -33,7 +33,7 @@ } bb2: { - _0 = const (); // scope 1 at $DIR/unreachable_diverging.rs:14:5: 19:6 + _0 = const (); // scope 1 at $DIR/unreachable_diverging.rs:19:6: 19:6 StorageDead(_1); // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2 StorageDead(_2); // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2 return; // scope 0 at $DIR/unreachable_diverging.rs:20:2: 20:2 @@ -50,7 +50,7 @@ } bb4: { -- _5 = const (); // scope 2 at $DIR/unreachable_diverging.rs:15:9: 17:10 +- _5 = const (); // scope 2 at $DIR/unreachable_diverging.rs:17:10: 17:10 - goto -> bb6; // scope 2 at $DIR/unreachable_diverging.rs:15:9: 17:10 - } - diff --git a/src/test/run-make-fulldeps/coverage-llvmir-deadcode/Makefile b/src/test/run-make-fulldeps/coverage-llvmir-deadcode/Makefile deleted file mode 100644 index 30c7c0fbb5133..0000000000000 --- a/src/test/run-make-fulldeps/coverage-llvmir-deadcode/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# needs-profiler-support -# ignore-msvc - -# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 -LINK_DEAD_CODE=yes - --include ../coverage-llvmir-base/Makefile - -# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and -# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. -# See ../coverage/coverage_tools.mk for more information. diff --git a/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile b/src/test/run-make-fulldeps/coverage-llvmir/Makefile similarity index 72% rename from src/test/run-make-fulldeps/coverage-llvmir-base/Makefile rename to src/test/run-make-fulldeps/coverage-llvmir/Makefile index 219ba15ad116d..54fc3d168645f 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile +++ b/src/test/run-make-fulldeps/coverage-llvmir/Makefile @@ -1,12 +1,8 @@ # needs-profiler-support -# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and -# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. -# See ../coverage/coverage_tools.mk for more information. - -include ../coverage/coverage_tools.mk -BASEDIR=../coverage-llvmir-base +BASEDIR=../coverage-llvmir ifeq ($(UNAME),Darwin) INSTR_PROF_DATA_SUFFIX=,regular,live_support @@ -20,11 +16,7 @@ else COMDAT_IF_SUPPORTED=, comdat endif -ifeq ($(LINK_DEAD_CODE),yes) - DEFINE_INTERNAL=define hidden -else - DEFINE_INTERNAL=define internal -endif +DEFINE_INTERNAL=define internal ifdef IS_WINDOWS LLVM_FILECHECK_OPTIONS=\ @@ -65,14 +57,8 @@ endif test_llvm_ir: # Compile the test program with non-experimental coverage instrumentation, and generate LLVM IR - # - # Note: `-Clink-dead-code=no` disables the option, needed because the option is automatically - # enabled for some platforms, but not for Windows MSVC (due to Issue #76038). The state of this - # option affects the generated MIR and coverage, so it is enabled for tests to ensure the - # tests results are the same across platforms. $(RUSTC) $(BASEDIR)/testprog.rs \ -Zinstrument-coverage \ - -Clink-dead-code=$(LINK_DEAD_CODE) \ --emit=llvm-ir cat "$(TMPDIR)"/testprog.ll | \ diff --git a/src/test/run-make-fulldeps/coverage-llvmir-base/filecheck.testprog.txt b/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-llvmir-base/filecheck.testprog.txt rename to src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt diff --git a/src/test/run-make-fulldeps/coverage-llvmir-base/testprog.rs b/src/test/run-make-fulldeps/coverage-llvmir/testprog.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage-llvmir-base/testprog.rs rename to src/test/run-make-fulldeps/coverage-llvmir/testprog.rs diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.closure.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.closure.json deleted file mode 100644 index bff55300b3ca3..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.closure.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/closure.rs", - "summary": { - "functions": { - "count": 5, - "covered": 3, - "percent": 60 - }, - "instantiations": { - "count": 5, - "covered": 3, - "percent": 60 - }, - "lines": { - "count": 91, - "covered": 77, - "percent": 84.61538461538461 - }, - "regions": { - "count": 25, - "covered": 13, - "notcovered": 12, - "percent": 52 - } - } - } - ], - "totals": { - "functions": { - "count": 5, - "covered": 3, - "percent": 60 - }, - "instantiations": { - "count": 5, - "covered": 3, - "percent": 60 - }, - "lines": { - "count": 91, - "covered": 77, - "percent": 84.61538461538461 - }, - "regions": { - "count": 25, - "covered": 13, - "notcovered": 12, - "percent": 52 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.conditions.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.conditions.json deleted file mode 100644 index ed937a1b13f38..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.conditions.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/conditions.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 49, - "covered": 23, - "percent": 46.93877551020408 - }, - "regions": { - "count": 69, - "covered": 18, - "notcovered": 51, - "percent": 26.08695652173913 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 49, - "covered": 23, - "percent": 46.93877551020408 - }, - "regions": { - "count": 69, - "covered": 18, - "notcovered": 51, - "percent": 26.08695652173913 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if.json deleted file mode 100644 index 84dcc251f3f4b..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/if.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 19, - "covered": 19, - "percent": 100 - }, - "regions": { - "count": 5, - "covered": 4, - "notcovered": 1, - "percent": 80 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 19, - "covered": 19, - "percent": 100 - }, - "regions": { - "count": 5, - "covered": 4, - "notcovered": 1, - "percent": 80 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json deleted file mode 100644 index c178e7f93476f..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/inner_items.rs", - "summary": { - "functions": { - "count": 4, - "covered": 4, - "percent": 100 - }, - "instantiations": { - "count": 4, - "covered": 4, - "percent": 100 - }, - "lines": { - "count": 26, - "covered": 26, - "percent": 100 - }, - "regions": { - "count": 15, - "covered": 13, - "notcovered": 2, - "percent": 86.66666666666667 - } - } - } - ], - "totals": { - "functions": { - "count": 4, - "covered": 4, - "percent": 100 - }, - "instantiations": { - "count": 4, - "covered": 4, - "percent": 100 - }, - "lines": { - "count": 26, - "covered": 26, - "percent": 100 - }, - "regions": { - "count": 15, - "covered": 13, - "notcovered": 2, - "percent": 86.66666666666667 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.lazy_boolean.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.lazy_boolean.json deleted file mode 100644 index 5a953b90b423f..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.lazy_boolean.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/lazy_boolean.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 40, - "covered": 30, - "percent": 75 - }, - "regions": { - "count": 37, - "covered": 26, - "notcovered": 11, - "percent": 70.27027027027027 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 40, - "covered": 30, - "percent": 75 - }, - "regions": { - "count": 37, - "covered": 26, - "notcovered": 11, - "percent": 70.27027027027027 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.nested_loops.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.nested_loops.json deleted file mode 100644 index 68163eb763619..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.nested_loops.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/nested_loops.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 21, - "covered": 16, - "percent": 76.19047619047619 - }, - "regions": { - "count": 18, - "covered": 14, - "notcovered": 4, - "percent": 77.77777777777779 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 21, - "covered": 16, - "percent": 76.19047619047619 - }, - "regions": { - "count": 18, - "covered": 14, - "notcovered": 4, - "percent": 77.77777777777779 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_loop.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_loop.json deleted file mode 100644 index ada6bb062dd1e..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_loop.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/simple_loop.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 19, - "covered": 19, - "percent": 100 - }, - "regions": { - "count": 9, - "covered": 8, - "notcovered": 1, - "percent": 88.88888888888889 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 19, - "covered": 19, - "percent": 100 - }, - "regions": { - "count": 9, - "covered": 8, - "notcovered": 1, - "percent": 88.88888888888889 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_match.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_match.json deleted file mode 100644 index 63d1ae74c5f5d..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_match.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/simple_match.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 24, - "covered": 24, - "percent": 100 - }, - "regions": { - "count": 15, - "covered": 14, - "notcovered": 1, - "percent": 93.33333333333333 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 24, - "covered": 24, - "percent": 100 - }, - "regions": { - "count": 15, - "covered": 14, - "notcovered": 1, - "percent": 93.33333333333333 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.closure.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.closure.txt deleted file mode 100644 index aef26a62e25fb..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.closure.txt +++ /dev/null @@ -1,94 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| let is_false = ! is_true; - 9| 1| - 10| 1| let mut some_string = Some(String::from("the string content")); - 11| 1| println!( - 12| 1| "The string or alt: {}" - 13| 1| , - 14| 1| some_string - 15| 1| . - 16| 1| unwrap_or_else - 17| 1| ( - 18| 1| || - 19| | { - 20| 0| let mut countdown = 0; - 21| 0| if is_false { - 22| 0| countdown = 10; - 23| 0| } - 24| 0| "alt string 1".to_owned() - 25| 1| } - 26| 1| ) - 27| 1| ); - 28| 1| - 29| 1| some_string = Some(String::from("the string content")); - 30| 1| let - 31| 1| a - 32| 1| = - 33| 1| || - 34| | { - 35| 0| let mut countdown = 0; - 36| 0| if is_false { - 37| 0| countdown = 10; - 38| 0| } - 39| 0| "alt string 2".to_owned() - 40| 1| }; - 41| 1| println!( - 42| 1| "The string or alt: {}" - 43| 1| , - 44| 1| some_string - 45| 1| . - 46| 1| unwrap_or_else - 47| 1| ( - 48| 1| a - 49| 1| ) - 50| 1| ); - 51| 1| - 52| 1| some_string = None; - 53| 1| println!( - 54| 1| "The string or alt: {}" - 55| 1| , - 56| 1| some_string - 57| 1| . - 58| 1| unwrap_or_else - 59| 1| ( - 60| 1| || - 61| | { - 62| 1| let mut countdown = 0; - 63| 1| if is_false { - 64| 0| countdown = 10; - 65| 1| } - 66| 1| "alt string 3".to_owned() - 67| 1| } - 68| 1| ) - 69| 1| ); - 70| 1| - 71| 1| some_string = None; - 72| 1| let - 73| 1| a - 74| 1| = - 75| 1| || - 76| | { - 77| 1| let mut countdown = 0; - 78| 1| if is_false { - 79| 0| countdown = 10; - 80| 1| } - 81| 1| "alt string 4".to_owned() - 82| 1| }; - 83| 1| println!( - 84| 1| "The string or alt: {}" - 85| 1| , - 86| 1| some_string - 87| 1| . - 88| 1| unwrap_or_else - 89| 1| ( - 90| 1| a - 91| 1| ) - 92| 1| ); - 93| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.conditions.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.conditions.txt deleted file mode 100644 index 173ff4aa4c481..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.conditions.txt +++ /dev/null @@ -1,69 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| |fn main() { - 4| 1| let mut countdown = 0; - 5| 1| if true { - 6| 1| countdown = 10; - 7| 1| } - 8| | - 9| | const B: u32 = 100; - 10| 1| let x = if countdown > 7 { - 11| 1| countdown -= 4; - 12| 1| B - 13| 0| } else if countdown > 2 { - 14| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 15| 0| countdown = 0; - 16| 0| } - 17| 0| countdown -= 5; - 18| 0| countdown - 19| | } else { - 20| 0| return; - 21| | }; - 22| | - 23| 1| let mut countdown = 0; - 24| 1| if true { - 25| 1| countdown = 10; - 26| 1| } - 27| | - 28| 1| if countdown > 7 { - 29| 1| countdown -= 4; - 30| 0| } else if countdown > 2 { - 31| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 32| 0| countdown = 0; - 33| 0| } - 34| 0| countdown -= 5; - 35| | } else { - 36| 0| return; - 37| | } - 38| | - 39| 1| let mut countdown = 0; - 40| 1| if true { - 41| 1| countdown = 1; - 42| 1| } - 43| | - 44| 1| let z = if countdown > 7 { - ^0 - 45| 0| countdown -= 4; - 46| 1| } else if countdown > 2 { - 47| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 48| 0| countdown = 0; - 49| 0| } - 50| 0| countdown -= 5; - 51| | } else { - 52| 1| let should_be_reachable = countdown; - 53| 1| println!("reached"); - 54| 1| return; - 55| | }; - 56| | - 57| 0| let w = if countdown > 7 { - 58| 0| countdown -= 4; - 59| 0| } else if countdown > 2 { - 60| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 61| 0| countdown = 0; - 62| 0| } - 63| 0| countdown -= 5; - 64| | } else { - 65| 0| return; - 66| | }; - 67| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if_else.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if_else.txt deleted file mode 100644 index 5f899723e2554..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if_else.txt +++ /dev/null @@ -1,41 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| | - 3| |fn main() { - 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| | // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut countdown = 0; - 10| 1| if - 11| 1| is_true - 12| 1| { - 13| 1| countdown - 14| 1| = - 15| 1| 10 - 16| 1| ; - 17| 1| } - 18| | else // Note coverage region difference without semicolon - 19| | { - 20| 0| countdown - 21| 0| = - 22| 0| 100 - 23| | } - 24| | - 25| | if - 26| 1| is_true - 27| 1| { - 28| 1| countdown - 29| 1| = - 30| 1| 10 - 31| 1| ; - 32| 1| } - 33| | else - 34| 0| { - 35| 0| countdown - 36| 0| = - 37| 0| 100 - 38| 0| ; - 39| 0| } - 40| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt deleted file mode 100644 index 4a51f842a4bb2..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt +++ /dev/null @@ -1,60 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| |fn main() { - 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| | // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut countdown = 0; - 10| 1| if is_true { - 11| 1| countdown = 10; - 12| 1| } - ^0 - 13| | - 14| | mod in_mod { - 15| | const IN_MOD_CONST: u32 = 1000; - 16| | } - 17| | - 18| | fn in_func(a: u32) { - 19| 3| let b = 1; - 20| 3| let c = a + b; - 21| 3| println!("c = {}", c) - 22| 3| } - 23| | - 24| | struct InStruct { - 25| | in_struct_field: u32, - 26| | } - 27| | - 28| | const IN_CONST: u32 = 1234; - 29| | - 30| | trait InTrait { - 31| | fn trait_func(&mut self, incr: u32); - 32| | - 33| 1| fn default_trait_func(&mut self) { - 34| 1| in_func(IN_CONST); - 35| 1| self.trait_func(IN_CONST); - 36| 1| } - 37| | } - 38| | - 39| | impl InTrait for InStruct { - 40| | fn trait_func(&mut self, incr: u32) { - 41| 1| self.in_struct_field += incr; - 42| 1| in_func(self.in_struct_field); - 43| 1| } - 44| | } - 45| | - 46| | type InType = String; - 47| | - 48| 1| if is_true { - 49| 1| in_func(countdown); - 50| 1| } - ^0 - 51| | - 52| 1| let mut val = InStruct { - 53| 1| in_struct_field: 101, - 54| 1| }; - 55| 1| - 56| 1| val.default_trait_func(); - 57| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.partial_eq.txt deleted file mode 100644 index 310bf13a695af..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.partial_eq.txt +++ /dev/null @@ -1,101 +0,0 @@ - 1| |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the - 2| |// structure of this test. - 3| | - 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] - ^1 ^1 - 5| |pub struct Version { - 6| | major: usize, - 7| 1| minor: usize, - 8| | patch: usize, - 9| |} - 10| | - 11| |impl Version { - 12| | pub fn new(major: usize, minor: usize, patch: usize) -> Self { - 13| 2| Self { - 14| 2| major, - 15| 2| minor, - 16| 2| patch, - 17| 2| } - 18| 2| } - 19| |} - 20| | - 21| 1|fn main() { - 22| 1| let version_3_2_1 = Version::new(3, 2, 1); - 23| 1| let version_3_3_0 = Version::new(3, 3, 0); - 24| 1| - 25| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); - 26| 1|} - 27| | - 28| |/* - 29| | - 30| |This test verifies a bug was fixed that otherwise generated this error: - 31| | - 32| |thread 'rustc' panicked at 'No counters provided the source_hash for function: - 33| | Instance { - 34| | def: Item(WithOptConstParam { - 35| | did: DefId(0:101 ~ autocfg[c44a]::version::{impl#2}::partial_cmp), - 36| | const_param_did: None - 37| | }), - 38| | substs: [] - 39| | }' - 40| |The `PartialOrd` derived by `Version` happened to generate a MIR that generated coverage - 41| |without a code region associated with any `Counter`. Code regions were associated with at least - 42| |one expression, which is allowed, but the `function_source_hash` was only passed to the codegen - 43| |(coverage mapgen) phase from a `Counter`s code region. A new method was added to pass the - 44| |`function_source_hash` without a code region, if necessary. - 45| | - 46| |*/ - 47| | - 48| |// FIXME(richkadel): It may be worth investigating why the coverage report for this test produces - 49| |// the following results: - 50| | - 51| |/* - 52| | - 53| |1. Why are their two counts below different characters (first and last) of `PartialOrd`, on line 17? - 54| | - 55| |2. Line 17 is counted twice, but the `::lt` instance shows a line count of 1? Is there a missing - 56| | line count with a different instance? Or was it really only called once? - 57| | - 58| |3. Line 20 shows another line count (of 1) for a line within a `struct` declaration (on only one of - 59| | its 3 fields). I doubt the specific field (`minor`) is relevant, but rather I suspect there's a - 60| | problem computing the file position here, for some reason. - 61| | - 62| | - 63| | 16| | - 64| | 17| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] - 65| | ^1 ^1 - 66| |------------------ - 67| ||Unexecuted instantiation: ::gt - 68| |------------------ - 69| ||Unexecuted instantiation: ::le - 70| |------------------ - 71| ||Unexecuted instantiation: ::ge - 72| |------------------ - 73| ||::lt: - 74| || 17| 1|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] - 75| |------------------ - 76| | 18| |pub struct Version { - 77| | 19| | major: usize, - 78| | 20| 1| minor: usize, - 79| | 21| | patch: usize, - 80| | 22| |} - 81| | 23| | - 82| | 24| |impl Version { - 83| | 25| | pub fn new(major: usize, minor: usize, patch: usize) -> Self { - 84| | 26| 2| Version { - 85| | 27| 2| major, - 86| | 28| 2| minor, - 87| | 29| 2| patch, - 88| | 30| 2| } - 89| | 31| 2| } - 90| | 32| |} - 91| | 33| | - 92| | 34| 1|fn main() { - 93| | 35| 1| let version_3_2_1 = Version::new(3, 2, 1); - 94| | 36| 1| let version_3_3_0 = Version::new(3, 3, 0); - 95| | 37| 1| - 96| | 38| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version - 97| |_3_3_0); - 98| | 39| 1|} - 99| |*/ - diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_loop.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_loop.txt deleted file mode 100644 index 064930dd75c93..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_loop.txt +++ /dev/null @@ -1,37 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| | - 3| |fn main() { - 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| | // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut countdown = 0; - 10| | - 11| | if - 12| 1| is_true - 13| 1| { - 14| 1| countdown - 15| 1| = - 16| 1| 10 - 17| 1| ; - 18| 1| } - ^0 - 19| | - 20| | loop - 21| | { - 22| | if - 23| 11| countdown - 24| 11| == - 25| 11| 0 - 26| | { - 27| 1| break - 28| | ; - 29| | } - 30| 10| countdown - 31| 10| -= - 32| 10| 1 - 33| | ; - 34| 1| } - 35| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_match.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_match.txt deleted file mode 100644 index 1f7e71d3eb0e7..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_match.txt +++ /dev/null @@ -1,46 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| | - 3| |fn main() { - 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| | // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut countdown = 1; - 10| 1| if is_true { - 11| 1| countdown = 0; - 12| 1| } - ^0 - 13| | - 14| | for - 15| 2| _ - 16| | in - 17| 3| 0..2 - 18| | { - 19| | let z - 20| | ; - 21| | match - 22| 2| countdown - 23| | { - 24| 1| x - 25| | if - 26| 2| x - 27| 2| < - 28| 2| 1 - ^1 - 29| | => - 30| 1| { - 31| 1| z = countdown - 32| 1| ; - 33| 1| let y = countdown - 34| 1| ; - 35| 1| countdown = 10 - 36| 1| ; - 37| 1| } - 38| | _ - 39| | => - 40| 1| {} - 41| | } - 42| 3| } - 43| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.try_error_result.txt deleted file mode 100644 index 6b3a8c39c6338..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.try_error_result.txt +++ /dev/null @@ -1,38 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| |// expect-exit-status-1 - 3| | - 4| |fn call(return_error: bool) -> Result<(),()> { - 5| 6| if return_error { - 6| 1| Err(()) - 7| | } else { - 8| 5| Ok(()) - 9| | } - 10| 6|} - 11| | - 12| |fn main() -> Result<(),()> { - 13| 1| let mut - 14| 1| countdown = 10 - 15| | ; - 16| | for - 17| 6| _ - 18| | in - 19| 6| 0..10 - 20| | { - 21| 6| countdown - 22| 6| -= 1 - 23| 6| ; - 24| 6| if - 25| 6| countdown < 5 - 26| | { - 27| 1| call(/*return_error=*/ true)?; - 28| 0| call(/*return_error=*/ false)?; - 29| | } - 30| | else - 31| | { - 32| 5| call(/*return_error=*/ false)?; - ^0 - 33| 5| } - 34| 5| } - 35| 0| Ok(()) - 36| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.closure.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.closure.txt deleted file mode 100644 index fb797796e4e7d..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.closure.txt +++ /dev/null @@ -1,94 +0,0 @@ -Counter in file 0 20:21 -> 20:38, #1 -Counter in file 0 21:20 -> 21:28, (#1 + 0) -Counter in file 0 21:29 -> 23:18, #2 -Counter in file 0 23:18 -> 23:19, (#1 - #2) -Counter in file 0 24:17 -> 25:14, (#2 + (#1 - #2)) -Counter in file 0 3:11 -> 18:13, #1 -Counter in file 0 25:14 -> 33:9, (#1 + 0) -Counter in file 0 40:6 -> 60:13, (#1 + 0) -Counter in file 0 67:14 -> 75:9, (#1 + 0) -Counter in file 0 82:6 -> 93:2, (#1 + 0) -Counter in file 0 77:13 -> 77:30, #1 -Counter in file 0 78:12 -> 78:20, (#1 + 0) -Counter in file 0 78:21 -> 80:10, #2 -Counter in file 0 80:10 -> 80:11, (#1 - #2) -Counter in file 0 81:9 -> 82:6, (#2 + (#1 - #2)) -Counter in file 0 62:21 -> 62:38, #1 -Counter in file 0 63:20 -> 63:28, (#1 + 0) -Counter in file 0 63:29 -> 65:18, #2 -Counter in file 0 65:18 -> 65:19, (#1 - #2) -Counter in file 0 66:17 -> 67:14, (#2 + (#1 - #2)) -Counter in file 0 35:13 -> 35:30, #1 -Counter in file 0 36:12 -> 36:20, (#1 + 0) -Counter in file 0 36:21 -> 38:10, #2 -Counter in file 0 38:10 -> 38:11, (#1 - #2) -Counter in file 0 39:9 -> 40:6, (#2 + (#1 - #2)) -Emitting segments for file: ../coverage/closure.rs -Combined regions: - 3:11 -> 18:13 (count=1) - 20:21 -> 20:38 (count=0) - 21:20 -> 21:28 (count=0) - 21:29 -> 23:18 (count=0) - 23:18 -> 23:19 (count=0) - 24:17 -> 25:14 (count=0) - 25:14 -> 33:9 (count=1) - 35:13 -> 35:30 (count=0) - 36:12 -> 36:20 (count=0) - 36:21 -> 38:10 (count=0) - 38:10 -> 38:11 (count=0) - 39:9 -> 40:6 (count=0) - 40:6 -> 60:13 (count=1) - 62:21 -> 62:38 (count=1) - 63:20 -> 63:28 (count=1) - 63:29 -> 65:18 (count=0) - 65:18 -> 65:19 (count=1) - 66:17 -> 67:14 (count=1) - 67:14 -> 75:9 (count=1) - 77:13 -> 77:30 (count=1) - 78:12 -> 78:20 (count=1) - 78:21 -> 80:10 (count=0) - 80:10 -> 80:11 (count=1) - 81:9 -> 82:6 (count=1) - 82:6 -> 93:2 (count=1) -Segment at 3:11 (count = 1), RegionEntry -Segment at 18:13 (count = 0), Skipped -Segment at 20:21 (count = 0), RegionEntry -Segment at 20:38 (count = 0), Skipped -Segment at 21:20 (count = 0), RegionEntry -Segment at 21:28 (count = 0), Skipped -Segment at 21:29 (count = 0), RegionEntry -Segment at 23:18 (count = 0), RegionEntry -Segment at 23:19 (count = 0), Skipped -Segment at 24:17 (count = 0), RegionEntry -Segment at 25:14 (count = 1), RegionEntry -Segment at 33:9 (count = 0), Skipped -Segment at 35:13 (count = 0), RegionEntry -Segment at 35:30 (count = 0), Skipped -Segment at 36:12 (count = 0), RegionEntry -Segment at 36:20 (count = 0), Skipped -Segment at 36:21 (count = 0), RegionEntry -Segment at 38:10 (count = 0), RegionEntry -Segment at 38:11 (count = 0), Skipped -Segment at 39:9 (count = 0), RegionEntry -Segment at 40:6 (count = 1), RegionEntry -Segment at 60:13 (count = 0), Skipped -Segment at 62:21 (count = 1), RegionEntry -Segment at 62:38 (count = 0), Skipped -Segment at 63:20 (count = 1), RegionEntry -Segment at 63:28 (count = 0), Skipped -Segment at 63:29 (count = 0), RegionEntry -Segment at 65:18 (count = 1), RegionEntry -Segment at 65:19 (count = 0), Skipped -Segment at 66:17 (count = 1), RegionEntry -Segment at 67:14 (count = 1), RegionEntry -Segment at 75:9 (count = 0), Skipped -Segment at 77:13 (count = 1), RegionEntry -Segment at 77:30 (count = 0), Skipped -Segment at 78:12 (count = 1), RegionEntry -Segment at 78:20 (count = 0), Skipped -Segment at 78:21 (count = 0), RegionEntry -Segment at 80:10 (count = 1), RegionEntry -Segment at 80:11 (count = 0), Skipped -Segment at 81:9 (count = 1), RegionEntry -Segment at 82:6 (count = 1), RegionEntry -Segment at 93:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.conditions.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.conditions.txt deleted file mode 100644 index d48cd8074bebb..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.conditions.txt +++ /dev/null @@ -1,238 +0,0 @@ -Counter in file 0 4:9 -> 4:26, #1 -Counter in file 0 5:8 -> 5:12, (#1 + 0) -Counter in file 0 5:13 -> 7:6, #2 -Counter in file 0 10:9 -> 10:10, (#4 + #11) -Counter in file 0 10:16 -> 10:29, (#2 + 0) -Counter in file 0 11:9 -> 12:10, #4 -Counter in file 0 13:15 -> 13:28, ((#2 + 0) - #3) -Counter in file 0 14:12 -> 14:25, #5 -Counter in file 0 14:29 -> 14:42, (#5 - #13) -Counter in file 0 14:42 -> 14:43, (#13 + #14) -Counter in file 0 14:42 -> 14:43, ((#5 - #13) - #14) -Counter in file 0 14:46 -> 14:60, #21 -Counter in file 0 14:60 -> 14:61, (#17 + #18) -Counter in file 0 14:60 -> 14:61, (#21 - #18) -Counter in file 0 14:61 -> 16:10, #22 -Counter in file 0 16:10 -> 16:11, #23 -Counter in file 0 17:9 -> 18:18, #11 -Counter in file 0 20:9 -> 20:15, (((#2 + 0) - #3) - #5) -Counter in file 0 23:9 -> 23:26, ((#4 + #11) + 0) -Counter in file 0 24:8 -> 24:12, ((#4 + #11) + 0) -Counter in file 0 24:13 -> 26:6, #12 -Counter in file 0 28:8 -> 28:21, (#12 + 0) -Counter in file 0 29:9 -> 29:23, #16 -Counter in file 0 30:15 -> 30:28, ((#12 + 0) - #15) -Counter in file 0 31:12 -> 31:25, (((#12 + 0) - #15) - #8) -Counter in file 0 31:29 -> 31:42, ((((#12 + 0) - #15) - #8) - #24) -Counter in file 0 31:42 -> 31:43, (((((#12 + 0) - #15) - #8) - #24) - #25) -Counter in file 0 31:42 -> 31:43, (#24 + #25) -Counter in file 0 31:46 -> 31:60, #32 -Counter in file 0 31:60 -> 31:61, (#28 + #29) -Counter in file 0 31:60 -> 31:61, (#32 - #29) -Counter in file 0 31:61 -> 33:10, #33 -Counter in file 0 33:10 -> 33:11, #34 -Counter in file 0 34:9 -> 34:23, #19 -Counter in file 0 36:9 -> 36:15, #8 -Counter in file 0 39:9 -> 39:26, (#16 + #19) -Counter in file 0 40:8 -> 40:12, ((#16 + #19) + 0) -Counter in file 0 40:13 -> 42:6, #20 -Counter in file 0 44:9 -> 44:10, (#27 + #30) -Counter in file 0 44:16 -> 44:29, (#20 + 0) -Counter in file 0 45:9 -> 45:23, #27 -Counter in file 0 46:15 -> 46:28, ((#20 + 0) - #26) -Counter in file 0 47:12 -> 47:25, (((#20 + 0) - #26) - #7) -Counter in file 0 47:29 -> 47:42, ((((#20 + 0) - #26) - #7) - #35) -Counter in file 0 47:42 -> 47:43, (#35 + #36) -Counter in file 0 47:42 -> 47:43, (((((#20 + 0) - #26) - #7) - #35) - #36) -Counter in file 0 47:46 -> 47:60, #41 -Counter in file 0 47:60 -> 47:61, (#37 + #38) -Counter in file 0 47:60 -> 47:61, (#41 - #38) -Counter in file 0 47:61 -> 49:10, #42 -Counter in file 0 49:10 -> 49:11, #43 -Counter in file 0 50:9 -> 50:23, #30 -Counter in file 0 52:13 -> 54:15, #7 -Counter in file 0 57:9 -> 57:10, (#9 + #10) -Counter in file 0 57:16 -> 57:29, ((#27 + #30) + 0) -Counter in file 0 58:9 -> 58:23, #9 -Counter in file 0 59:15 -> 59:28, ((#27 + #30) - #31) -Counter in file 0 60:12 -> 60:25, (((#27 + #30) - #31) - #6) -Counter in file 0 60:29 -> 60:42, ((((#27 + #30) - #31) - #6) - #39) -Counter in file 0 60:42 -> 60:43, (#39 + #40) -Counter in file 0 60:42 -> 60:43, (((((#27 + #30) - #31) - #6) - #39) - #40) -Counter in file 0 60:46 -> 60:60, #46 -Counter in file 0 60:60 -> 60:61, (#46 - #45) -Counter in file 0 60:60 -> 60:61, (#44 + #45) -Counter in file 0 60:61 -> 62:10, #47 -Counter in file 0 62:10 -> 62:11, #48 -Counter in file 0 63:9 -> 63:23, #10 -Counter in file 0 65:9 -> 65:15, #6 -Counter in file 0 67:1 -> 67:2, ((#9 + #10) + (((#6 + #7) + #8) + (((#2 + 0) - #3) - #5))) -Emitting segments for file: ../coverage/conditions.rs -Combined regions: - 4:9 -> 4:26 (count=1) - 5:8 -> 5:12 (count=1) - 5:13 -> 7:6 (count=1) - 10:9 -> 10:10 (count=1) - 10:16 -> 10:29 (count=1) - 11:9 -> 12:10 (count=1) - 13:15 -> 13:28 (count=0) - 14:12 -> 14:25 (count=0) - 14:29 -> 14:42 (count=0) - 14:42 -> 14:43 (count=0) - 14:46 -> 14:60 (count=0) - 14:60 -> 14:61 (count=0) - 14:61 -> 16:10 (count=0) - 16:10 -> 16:11 (count=0) - 17:9 -> 18:18 (count=0) - 20:9 -> 20:15 (count=0) - 23:9 -> 23:26 (count=1) - 24:8 -> 24:12 (count=1) - 24:13 -> 26:6 (count=1) - 28:8 -> 28:21 (count=1) - 29:9 -> 29:23 (count=1) - 30:15 -> 30:28 (count=0) - 31:12 -> 31:25 (count=0) - 31:29 -> 31:42 (count=0) - 31:42 -> 31:43 (count=0) - 31:46 -> 31:60 (count=0) - 31:60 -> 31:61 (count=0) - 31:61 -> 33:10 (count=0) - 33:10 -> 33:11 (count=0) - 34:9 -> 34:23 (count=0) - 36:9 -> 36:15 (count=0) - 39:9 -> 39:26 (count=1) - 40:8 -> 40:12 (count=1) - 40:13 -> 42:6 (count=1) - 44:9 -> 44:10 (count=0) - 44:16 -> 44:29 (count=1) - 45:9 -> 45:23 (count=0) - 46:15 -> 46:28 (count=1) - 47:12 -> 47:25 (count=0) - 47:29 -> 47:42 (count=0) - 47:42 -> 47:43 (count=0) - 47:46 -> 47:60 (count=0) - 47:60 -> 47:61 (count=0) - 47:61 -> 49:10 (count=0) - 49:10 -> 49:11 (count=0) - 50:9 -> 50:23 (count=0) - 52:13 -> 54:15 (count=1) - 57:9 -> 57:10 (count=0) - 57:16 -> 57:29 (count=0) - 58:9 -> 58:23 (count=0) - 59:15 -> 59:28 (count=0) - 60:12 -> 60:25 (count=0) - 60:29 -> 60:42 (count=0) - 60:42 -> 60:43 (count=0) - 60:46 -> 60:60 (count=0) - 60:60 -> 60:61 (count=0) - 60:61 -> 62:10 (count=0) - 62:10 -> 62:11 (count=0) - 63:9 -> 63:23 (count=0) - 65:9 -> 65:15 (count=0) - 67:1 -> 67:2 (count=1) -Segment at 4:9 (count = 1), RegionEntry -Segment at 4:26 (count = 0), Skipped -Segment at 5:8 (count = 1), RegionEntry -Segment at 5:12 (count = 0), Skipped -Segment at 5:13 (count = 1), RegionEntry -Segment at 7:6 (count = 0), Skipped -Segment at 10:9 (count = 1), RegionEntry -Segment at 10:10 (count = 0), Skipped -Segment at 10:16 (count = 1), RegionEntry -Segment at 10:29 (count = 0), Skipped -Segment at 11:9 (count = 1), RegionEntry -Segment at 12:10 (count = 0), Skipped -Segment at 13:15 (count = 0), RegionEntry -Segment at 13:28 (count = 0), Skipped -Segment at 14:12 (count = 0), RegionEntry -Segment at 14:25 (count = 0), Skipped -Segment at 14:29 (count = 0), RegionEntry -Segment at 14:42 (count = 0), RegionEntry -Segment at 14:43 (count = 0), Skipped -Segment at 14:46 (count = 0), RegionEntry -Segment at 14:60 (count = 0), RegionEntry -Segment at 14:61 (count = 0), RegionEntry -Segment at 16:10 (count = 0), RegionEntry -Segment at 16:11 (count = 0), Skipped -Segment at 17:9 (count = 0), RegionEntry -Segment at 18:18 (count = 0), Skipped -Segment at 20:9 (count = 0), RegionEntry -Segment at 20:15 (count = 0), Skipped -Segment at 23:9 (count = 1), RegionEntry -Segment at 23:26 (count = 0), Skipped -Segment at 24:8 (count = 1), RegionEntry -Segment at 24:12 (count = 0), Skipped -Segment at 24:13 (count = 1), RegionEntry -Segment at 26:6 (count = 0), Skipped -Segment at 28:8 (count = 1), RegionEntry -Segment at 28:21 (count = 0), Skipped -Segment at 29:9 (count = 1), RegionEntry -Segment at 29:23 (count = 0), Skipped -Segment at 30:15 (count = 0), RegionEntry -Segment at 30:28 (count = 0), Skipped -Segment at 31:12 (count = 0), RegionEntry -Segment at 31:25 (count = 0), Skipped -Segment at 31:29 (count = 0), RegionEntry -Segment at 31:42 (count = 0), RegionEntry -Segment at 31:43 (count = 0), Skipped -Segment at 31:46 (count = 0), RegionEntry -Segment at 31:60 (count = 0), RegionEntry -Segment at 31:61 (count = 0), RegionEntry -Segment at 33:10 (count = 0), RegionEntry -Segment at 33:11 (count = 0), Skipped -Segment at 34:9 (count = 0), RegionEntry -Segment at 34:23 (count = 0), Skipped -Segment at 36:9 (count = 0), RegionEntry -Segment at 36:15 (count = 0), Skipped -Segment at 39:9 (count = 1), RegionEntry -Segment at 39:26 (count = 0), Skipped -Segment at 40:8 (count = 1), RegionEntry -Segment at 40:12 (count = 0), Skipped -Segment at 40:13 (count = 1), RegionEntry -Segment at 42:6 (count = 0), Skipped -Segment at 44:9 (count = 0), RegionEntry -Segment at 44:10 (count = 0), Skipped -Segment at 44:16 (count = 1), RegionEntry -Segment at 44:29 (count = 0), Skipped -Segment at 45:9 (count = 0), RegionEntry -Segment at 45:23 (count = 0), Skipped -Segment at 46:15 (count = 1), RegionEntry -Segment at 46:28 (count = 0), Skipped -Segment at 47:12 (count = 0), RegionEntry -Segment at 47:25 (count = 0), Skipped -Segment at 47:29 (count = 0), RegionEntry -Segment at 47:42 (count = 0), RegionEntry -Segment at 47:43 (count = 0), Skipped -Segment at 47:46 (count = 0), RegionEntry -Segment at 47:60 (count = 0), RegionEntry -Segment at 47:61 (count = 0), RegionEntry -Segment at 49:10 (count = 0), RegionEntry -Segment at 49:11 (count = 0), Skipped -Segment at 50:9 (count = 0), RegionEntry -Segment at 50:23 (count = 0), Skipped -Segment at 52:13 (count = 1), RegionEntry -Segment at 54:15 (count = 0), Skipped -Segment at 57:9 (count = 0), RegionEntry -Segment at 57:10 (count = 0), Skipped -Segment at 57:16 (count = 0), RegionEntry -Segment at 57:29 (count = 0), Skipped -Segment at 58:9 (count = 0), RegionEntry -Segment at 58:23 (count = 0), Skipped -Segment at 59:15 (count = 0), RegionEntry -Segment at 59:28 (count = 0), Skipped -Segment at 60:12 (count = 0), RegionEntry -Segment at 60:25 (count = 0), Skipped -Segment at 60:29 (count = 0), RegionEntry -Segment at 60:42 (count = 0), RegionEntry -Segment at 60:43 (count = 0), Skipped -Segment at 60:46 (count = 0), RegionEntry -Segment at 60:60 (count = 0), RegionEntry -Segment at 60:61 (count = 0), RegionEntry -Segment at 62:10 (count = 0), RegionEntry -Segment at 62:11 (count = 0), Skipped -Segment at 63:9 (count = 0), RegionEntry -Segment at 63:23 (count = 0), Skipped -Segment at 65:9 (count = 0), RegionEntry -Segment at 65:15 (count = 0), Skipped -Segment at 67:1 (count = 1), RegionEntry -Segment at 67:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.generics.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.generics.txt deleted file mode 100644 index 013a69ed3983a..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.generics.txt +++ /dev/null @@ -1,48 +0,0 @@ -Counter in file 0 17:24 -> 19:6, #1 -Counter in file 0 17:24 -> 19:6, #1 -Counter in file 0 23:9 -> 28:28, #1 -Counter in file 0 30:8 -> 30:12, (#1 + 0) -Counter in file 0 31:9 -> 32:22, #2 -Counter in file 0 38:1 -> 38:2, (#2 + 0) -Counter in file 0 10:49 -> 12:6, #1 -Counter in file 0 10:49 -> 12:6, #1 -Emitting segments for file: ../coverage/generics.rs -Combined regions: - 10:49 -> 12:6 (count=3) - 17:24 -> 19:6 (count=2) - 23:9 -> 28:28 (count=1) - 30:8 -> 30:12 (count=1) - 31:9 -> 32:22 (count=1) - 38:1 -> 38:2 (count=1) -Segment at 10:49 (count = 3), RegionEntry -Segment at 12:6 (count = 0), Skipped -Segment at 17:24 (count = 2), RegionEntry -Segment at 19:6 (count = 0), Skipped -Segment at 23:9 (count = 1), RegionEntry -Segment at 28:28 (count = 0), Skipped -Segment at 30:8 (count = 1), RegionEntry -Segment at 30:12 (count = 0), Skipped -Segment at 31:9 (count = 1), RegionEntry -Segment at 32:22 (count = 0), Skipped -Segment at 38:1 (count = 1), RegionEntry -Segment at 38:2 (count = 0), Skipped -Emitting segments for function: _RNvMCs4fqI2P2rA04_8genericsINtB2_8FireworkdE12set_strengthB2_ -Combined regions: - 10:49 -> 12:6 (count=2) -Segment at 10:49 (count = 2), RegionEntry -Segment at 12:6 (count = 0), Skipped -Emitting segments for function: _RNvMCs4fqI2P2rA04_8genericsINtB2_8FireworklE12set_strengthB2_ -Combined regions: - 10:49 -> 12:6 (count=1) -Segment at 10:49 (count = 1), RegionEntry -Segment at 12:6 (count = 0), Skipped -Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworklENtNtNtCs7f2nZg1zwMz_4core3ops4drop4Drop4dropB4_ -Combined regions: - 17:24 -> 19:6 (count=1) -Segment at 17:24 (count = 1), RegionEntry -Segment at 19:6 (count = 0), Skipped -Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworkdENtNtNtCs7f2nZg1zwMz_4core3ops4drop4Drop4dropB4_ -Combined regions: - 17:24 -> 19:6 (count=1) -Segment at 17:24 (count = 1), RegionEntry -Segment at 19:6 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.if.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.if.txt deleted file mode 100644 index c2bef365ea9d8..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.if.txt +++ /dev/null @@ -1,21 +0,0 @@ -Counter in file 0 8:5 -> 18:10, #1 -Counter in file 0 21:9 -> 21:16, (#1 + 0) -Counter in file 0 22:5 -> 27:6, #2 -Counter in file 0 27:6 -> 27:7, (#1 - #2) -Counter in file 0 28:1 -> 28:2, (#2 + (#1 - #2)) -Emitting segments for file: ../coverage/if.rs -Combined regions: - 8:5 -> 18:10 (count=1) - 21:9 -> 21:16 (count=1) - 22:5 -> 27:6 (count=1) - 27:6 -> 27:7 (count=0) - 28:1 -> 28:2 (count=1) -Segment at 8:5 (count = 1), RegionEntry -Segment at 18:10 (count = 0), Skipped -Segment at 21:9 (count = 1), RegionEntry -Segment at 21:16 (count = 0), Skipped -Segment at 22:5 (count = 1), RegionEntry -Segment at 27:6 (count = 0), RegionEntry -Segment at 27:7 (count = 0), Skipped -Segment at 28:1 (count = 1), RegionEntry -Segment at 28:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.if_else.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.if_else.txt deleted file mode 100644 index faf5c094bbaaa..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.if_else.txt +++ /dev/null @@ -1,30 +0,0 @@ -Counter in file 0 7:9 -> 11:16, #1 -Counter in file 0 12:5 -> 17:6, #2 -Counter in file 0 20:9 -> 22:16, (#1 - #2) -Counter in file 0 26:9 -> 26:16, (#2 + (#1 - #2)) -Counter in file 0 27:5 -> 32:6, #3 -Counter in file 0 34:5 -> 39:6, ((#2 + (#1 - #2)) - #3) -Counter in file 0 40:1 -> 40:2, (#3 + ((#2 + (#1 - #2)) - #3)) -Emitting segments for file: ../coverage/if_else.rs -Combined regions: - 7:9 -> 11:16 (count=1) - 12:5 -> 17:6 (count=1) - 20:9 -> 22:16 (count=0) - 26:9 -> 26:16 (count=1) - 27:5 -> 32:6 (count=1) - 34:5 -> 39:6 (count=0) - 40:1 -> 40:2 (count=1) -Segment at 7:9 (count = 1), RegionEntry -Segment at 11:16 (count = 0), Skipped -Segment at 12:5 (count = 1), RegionEntry -Segment at 17:6 (count = 0), Skipped -Segment at 20:9 (count = 0), RegionEntry -Segment at 22:16 (count = 0), Skipped -Segment at 26:9 (count = 1), RegionEntry -Segment at 26:16 (count = 0), Skipped -Segment at 27:5 (count = 1), RegionEntry -Segment at 32:6 (count = 0), Skipped -Segment at 34:5 (count = 0), RegionEntry -Segment at 39:6 (count = 0), Skipped -Segment at 40:1 (count = 1), RegionEntry -Segment at 40:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.inner_items.txt deleted file mode 100644 index 65cd6481af4cc..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.inner_items.txt +++ /dev/null @@ -1,60 +0,0 @@ -Counter in file 0 19:13 -> 19:18, #1 -Counter in file 0 20:13 -> 20:14, #2 -Counter in file 0 20:17 -> 20:22, (#1 + 0) -Counter in file 0 21:9 -> 22:6, (#2 + 0) -Counter in file 0 7:9 -> 9:26, #1 -Counter in file 0 10:8 -> 10:15, (#1 + 0) -Counter in file 0 10:16 -> 12:6, #2 -Counter in file 0 12:6 -> 12:7, (#1 - #2) -Counter in file 0 48:8 -> 48:15, (#2 + (#1 - #2)) -Counter in file 0 48:16 -> 50:6, #3 -Counter in file 0 50:6 -> 50:7, ((#2 + (#1 - #2)) - #3) -Counter in file 0 52:9 -> 57:2, (#3 + ((#2 + (#1 - #2)) - #3)) -Counter in file 0 33:42 -> 36:10, #1 -Counter in file 0 41:37 -> 41:41, #1 -Counter in file 0 42:13 -> 43:10, #2 -Emitting segments for file: ../coverage/inner_items.rs -Combined regions: - 7:9 -> 9:26 (count=1) - 10:8 -> 10:15 (count=1) - 10:16 -> 12:6 (count=1) - 12:6 -> 12:7 (count=0) - 19:13 -> 19:18 (count=3) - 20:13 -> 20:14 (count=3) - 20:17 -> 20:22 (count=3) - 21:9 -> 22:6 (count=3) - 33:42 -> 36:10 (count=1) - 41:37 -> 41:41 (count=1) - 42:13 -> 43:10 (count=1) - 48:8 -> 48:15 (count=1) - 48:16 -> 50:6 (count=1) - 50:6 -> 50:7 (count=0) - 52:9 -> 57:2 (count=1) -Segment at 7:9 (count = 1), RegionEntry -Segment at 9:26 (count = 0), Skipped -Segment at 10:8 (count = 1), RegionEntry -Segment at 10:15 (count = 0), Skipped -Segment at 10:16 (count = 1), RegionEntry -Segment at 12:6 (count = 0), RegionEntry -Segment at 12:7 (count = 0), Skipped -Segment at 19:13 (count = 3), RegionEntry -Segment at 19:18 (count = 0), Skipped -Segment at 20:13 (count = 3), RegionEntry -Segment at 20:14 (count = 0), Skipped -Segment at 20:17 (count = 3), RegionEntry -Segment at 20:22 (count = 0), Skipped -Segment at 21:9 (count = 3), RegionEntry -Segment at 22:6 (count = 0), Skipped -Segment at 33:42 (count = 1), RegionEntry -Segment at 36:10 (count = 0), Skipped -Segment at 41:37 (count = 1), RegionEntry -Segment at 41:41 (count = 0), Skipped -Segment at 42:13 (count = 1), RegionEntry -Segment at 43:10 (count = 0), Skipped -Segment at 48:8 (count = 1), RegionEntry -Segment at 48:15 (count = 0), Skipped -Segment at 48:16 (count = 1), RegionEntry -Segment at 50:6 (count = 0), RegionEntry -Segment at 50:7 (count = 0), Skipped -Segment at 52:9 (count = 1), RegionEntry -Segment at 57:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.lazy_boolean.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.lazy_boolean.txt deleted file mode 100644 index 8e56d79d9d2aa..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.lazy_boolean.txt +++ /dev/null @@ -1,131 +0,0 @@ -Counter in file 0 7:9 -> 9:42, #1 -Counter in file 0 10:8 -> 10:15, (#1 + 0) -Counter in file 0 10:16 -> 14:6, #2 -Counter in file 0 14:6 -> 14:7, (#1 - #2) -Counter in file 0 16:9 -> 16:17, ((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) -Counter in file 0 18:13 -> 18:18, (#2 + (#1 - #2)) -Counter in file 0 20:13 -> 20:18, ((#2 + (#1 - #2)) - #3) -Counter in file 0 20:18 -> 20:19, (#3 + #4) -Counter in file 0 20:18 -> 20:19, (((#2 + (#1 - #2)) - #3) - #4) -Counter in file 0 23:9 -> 23:17, ((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) -Counter in file 0 25:13 -> 25:18, (((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) + 0) -Counter in file 0 27:13 -> 27:18, (((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) -Counter in file 0 27:18 -> 27:19, (#5 + #6) -Counter in file 0 27:18 -> 27:19, ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6) -Counter in file 0 29:9 -> 29:17, ((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) -Counter in file 0 29:20 -> 29:25, (((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) + 0) -Counter in file 0 29:29 -> 29:34, #7 -Counter in file 0 29:34 -> 29:35, ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8) -Counter in file 0 29:34 -> 29:35, (#7 - #8) -Counter in file 0 30:9 -> 30:17, ((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) -Counter in file 0 30:20 -> 30:25, (((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) + 0) -Counter in file 0 30:29 -> 30:34, #9 -Counter in file 0 30:34 -> 30:35, ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10) -Counter in file 0 30:34 -> 30:35, (#9 - #10) -Counter in file 0 33:9 -> 34:16, (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) + 0) -Counter in file 0 35:5 -> 38:6, #11 -Counter in file 0 38:6 -> 38:7, (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11) -Counter in file 0 41:9 -> 41:16, (#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) -Counter in file 0 42:5 -> 45:6, #12 -Counter in file 0 47:5 -> 50:6, ((#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) - #12) -Counter in file 0 52:8 -> 52:16, (#12 + ((#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) - #12)) -Counter in file 0 52:17 -> 54:6, #13 -Counter in file 0 54:6 -> 54:7, ((#12 + ((#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) - #12)) - #13) -Counter in file 0 56:8 -> 56:15, (#13 + ((#12 + ((#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) - #12)) - #13)) -Counter in file 0 56:16 -> 58:6, #14 -Counter in file 0 58:12 -> 60:6, ((#13 + ((#12 + ((#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) - #12)) - #13)) - #14) -Counter in file 0 61:1 -> 61:2, (#14 + ((#13 + ((#12 + ((#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) - #12)) - #13)) - #14)) -Emitting segments for file: ../coverage/lazy_boolean.rs -Combined regions: - 7:9 -> 9:42 (count=1) - 10:8 -> 10:15 (count=1) - 10:16 -> 14:6 (count=1) - 14:6 -> 14:7 (count=0) - 16:9 -> 16:17 (count=1) - 18:13 -> 18:18 (count=1) - 20:13 -> 20:18 (count=0) - 20:18 -> 20:19 (count=1) - 23:9 -> 23:17 (count=1) - 25:13 -> 25:18 (count=1) - 27:13 -> 27:18 (count=1) - 27:18 -> 27:19 (count=1) - 29:9 -> 29:17 (count=1) - 29:20 -> 29:25 (count=1) - 29:29 -> 29:34 (count=1) - 29:34 -> 29:35 (count=1) - 30:9 -> 30:17 (count=1) - 30:20 -> 30:25 (count=1) - 30:29 -> 30:34 (count=0) - 30:34 -> 30:35 (count=1) - 33:9 -> 34:16 (count=1) - 35:5 -> 38:6 (count=0) - 38:6 -> 38:7 (count=1) - 41:9 -> 41:16 (count=1) - 42:5 -> 45:6 (count=1) - 47:5 -> 50:6 (count=0) - 52:8 -> 52:16 (count=1) - 52:17 -> 54:6 (count=0) - 54:6 -> 54:7 (count=1) - 56:8 -> 56:15 (count=1) - 56:16 -> 58:6 (count=1) - 58:12 -> 60:6 (count=0) - 61:1 -> 61:2 (count=1) -Segment at 7:9 (count = 1), RegionEntry -Segment at 9:42 (count = 0), Skipped -Segment at 10:8 (count = 1), RegionEntry -Segment at 10:15 (count = 0), Skipped -Segment at 10:16 (count = 1), RegionEntry -Segment at 14:6 (count = 0), RegionEntry -Segment at 14:7 (count = 0), Skipped -Segment at 16:9 (count = 1), RegionEntry -Segment at 16:17 (count = 0), Skipped -Segment at 18:13 (count = 1), RegionEntry -Segment at 18:18 (count = 0), Skipped -Segment at 20:13 (count = 0), RegionEntry -Segment at 20:18 (count = 1), RegionEntry -Segment at 20:19 (count = 0), Skipped -Segment at 23:9 (count = 1), RegionEntry -Segment at 23:17 (count = 0), Skipped -Segment at 25:13 (count = 1), RegionEntry -Segment at 25:18 (count = 0), Skipped -Segment at 27:13 (count = 1), RegionEntry -Segment at 27:18 (count = 1), RegionEntry -Segment at 27:19 (count = 0), Skipped -Segment at 29:9 (count = 1), RegionEntry -Segment at 29:17 (count = 0), Skipped -Segment at 29:20 (count = 1), RegionEntry -Segment at 29:25 (count = 0), Skipped -Segment at 29:29 (count = 1), RegionEntry -Segment at 29:34 (count = 1), RegionEntry -Segment at 29:35 (count = 0), Skipped -Segment at 30:9 (count = 1), RegionEntry -Segment at 30:17 (count = 0), Skipped -Segment at 30:20 (count = 1), RegionEntry -Segment at 30:25 (count = 0), Skipped -Segment at 30:29 (count = 0), RegionEntry -Segment at 30:34 (count = 1), RegionEntry -Segment at 30:35 (count = 0), Skipped -Segment at 33:9 (count = 1), RegionEntry -Segment at 34:16 (count = 0), Skipped -Segment at 35:5 (count = 0), RegionEntry -Segment at 38:6 (count = 1), RegionEntry -Segment at 38:7 (count = 0), Skipped -Segment at 41:9 (count = 1), RegionEntry -Segment at 41:16 (count = 0), Skipped -Segment at 42:5 (count = 1), RegionEntry -Segment at 45:6 (count = 0), Skipped -Segment at 47:5 (count = 0), RegionEntry -Segment at 50:6 (count = 0), Skipped -Segment at 52:8 (count = 1), RegionEntry -Segment at 52:16 (count = 0), Skipped -Segment at 52:17 (count = 0), RegionEntry -Segment at 54:6 (count = 1), RegionEntry -Segment at 54:7 (count = 0), Skipped -Segment at 56:8 (count = 1), RegionEntry -Segment at 56:15 (count = 0), Skipped -Segment at 56:16 (count = 1), RegionEntry -Segment at 58:6 (count = 0), Skipped -Segment at 58:12 (count = 0), RegionEntry -Segment at 60:6 (count = 0), Skipped -Segment at 61:1 (count = 1), RegionEntry -Segment at 61:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.nested_loops.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.nested_loops.txt deleted file mode 100644 index f503007353319..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.nested_loops.txt +++ /dev/null @@ -1,73 +0,0 @@ -Counter in file 0 2:9 -> 3:27, #1 -Counter in file 0 5:19 -> 5:32, (#1 + #2) -Counter in file 0 6:13 -> 7:24, ((#1 + #2) - #3) -Counter in file 0 8:13 -> 8:14, ((((#1 + #2) - #3) + (#5 + #6)) - #7) -Counter in file 0 8:18 -> 8:23, (((#1 + #2) - #3) + (#5 + #6)) -Counter in file 0 9:16 -> 9:22, (((((#1 + #2) - #3) + (#5 + #6)) - #7) + 0) -Counter in file 0 10:17 -> 10:22, #8 -Counter in file 0 12:13 -> 12:19, #9 -Counter in file 0 13:13 -> 13:19, #10 -Counter in file 0 14:16 -> 14:22, (#10 + 0) -Counter in file 0 15:17 -> 16:27, #11 -Counter in file 0 17:21 -> 17:33, #4 -Counter in file 0 19:21 -> 21:14, #5 -Counter in file 0 21:14 -> 21:15, #6 -Counter in file 0 22:10 -> 22:11, (#5 + #6) -Counter in file 0 23:9 -> 23:23, #2 -Counter in file 0 24:6 -> 24:7, #3 -Counter in file 0 25:1 -> 25:2, (#4 + #3) -Emitting segments for file: ../coverage/nested_loops.rs -Combined regions: - 2:9 -> 3:27 (count=1) - 5:19 -> 5:32 (count=1) - 6:13 -> 7:24 (count=1) - 8:13 -> 8:14 (count=3) - 8:18 -> 8:23 (count=3) - 9:16 -> 9:22 (count=3) - 10:17 -> 10:22 (count=0) - 12:13 -> 12:19 (count=3) - 13:13 -> 13:19 (count=3) - 14:16 -> 14:22 (count=3) - 15:17 -> 16:27 (count=1) - 17:21 -> 17:33 (count=1) - 19:21 -> 21:14 (count=0) - 21:14 -> 21:15 (count=2) - 22:10 -> 22:11 (count=2) - 23:9 -> 23:23 (count=0) - 24:6 -> 24:7 (count=0) - 25:1 -> 25:2 (count=1) -Segment at 2:9 (count = 1), RegionEntry -Segment at 3:27 (count = 0), Skipped -Segment at 5:19 (count = 1), RegionEntry -Segment at 5:32 (count = 0), Skipped -Segment at 6:13 (count = 1), RegionEntry -Segment at 7:24 (count = 0), Skipped -Segment at 8:13 (count = 3), RegionEntry -Segment at 8:14 (count = 0), Skipped -Segment at 8:18 (count = 3), RegionEntry -Segment at 8:23 (count = 0), Skipped -Segment at 9:16 (count = 3), RegionEntry -Segment at 9:22 (count = 0), Skipped -Segment at 10:17 (count = 0), RegionEntry -Segment at 10:22 (count = 0), Skipped -Segment at 12:13 (count = 3), RegionEntry -Segment at 12:19 (count = 0), Skipped -Segment at 13:13 (count = 3), RegionEntry -Segment at 13:19 (count = 0), Skipped -Segment at 14:16 (count = 3), RegionEntry -Segment at 14:22 (count = 0), Skipped -Segment at 15:17 (count = 1), RegionEntry -Segment at 16:27 (count = 0), Skipped -Segment at 17:21 (count = 1), RegionEntry -Segment at 17:33 (count = 0), Skipped -Segment at 19:21 (count = 0), RegionEntry -Segment at 21:14 (count = 2), RegionEntry -Segment at 21:15 (count = 0), Skipped -Segment at 22:10 (count = 2), RegionEntry -Segment at 22:11 (count = 0), Skipped -Segment at 23:9 (count = 0), RegionEntry -Segment at 23:23 (count = 0), Skipped -Segment at 24:6 (count = 0), RegionEntry -Segment at 24:7 (count = 0), Skipped -Segment at 25:1 (count = 1), RegionEntry -Segment at 25:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.partial_eq.txt deleted file mode 100644 index cdef821c0aef2..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.partial_eq.txt +++ /dev/null @@ -1,27 +0,0 @@ -Counter in file 0 7:5 -> 7:6, #1 -Counter in file 0 21:11 -> 26:2, #1 -Counter in file 0 4:17 -> 4:22, #1 -Counter in file 0 13:9 -> 18:6, #1 -Counter in file 0 4:39 -> 4:40, #1 -Counter in file 0 4:48 -> 4:49, (#1 + 0) -Counter in file 0 8:5 -> 8:17, #1 -Emitting segments for file: ../coverage/partial_eq.rs -Combined regions: - 4:17 -> 4:22 (count=2) - 4:39 -> 4:40 (count=1) - 4:48 -> 4:49 (count=1) - 7:5 -> 7:6 (count=1) - 13:9 -> 18:6 (count=2) - 21:11 -> 26:2 (count=1) -Segment at 4:17 (count = 2), RegionEntry -Segment at 4:22 (count = 0), Skipped -Segment at 4:39 (count = 1), RegionEntry -Segment at 4:40 (count = 0), Skipped -Segment at 4:48 (count = 1), RegionEntry -Segment at 4:49 (count = 0), Skipped -Segment at 7:5 (count = 1), RegionEntry -Segment at 7:6 (count = 0), Skipped -Segment at 13:9 (count = 2), RegionEntry -Segment at 18:6 (count = 0), Skipped -Segment at 21:11 (count = 1), RegionEntry -Segment at 26:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.tight_inf_loop.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.tight_inf_loop.txt deleted file mode 100644 index 5887658fe67a2..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.tight_inf_loop.txt +++ /dev/null @@ -1,10 +0,0 @@ -Counter in file 0 2:8 -> 2:13, #1 -Counter in file 0 5:1 -> 5:2, (#1 - #2) -Emitting segments for file: ../coverage/tight_inf_loop.rs -Combined regions: - 2:8 -> 2:13 (count=1) - 5:1 -> 5:2 (count=1) -Segment at 2:8 (count = 1), RegionEntry -Segment at 2:13 (count = 0), Skipped -Segment at 5:1 (count = 1), RegionEntry -Segment at 5:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.try_error_result.txt deleted file mode 100644 index a317cd792910d..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.try_error_result.txt +++ /dev/null @@ -1,72 +0,0 @@ -Counter in file 0 13:9 -> 14:23, #1 -Counter in file 0 17:9 -> 17:10, ((#1 + (#2 + #3)) - #4) -Counter in file 0 19:9 -> 19:14, (#1 + (#2 + #3)) -Counter in file 0 21:9 -> 25:26, #8 -Counter in file 0 27:13 -> 27:41, #9 -Counter in file 0 27:41 -> 27:42, #5 -Counter in file 0 28:13 -> 28:42, (#9 - #5) -Counter in file 0 28:42 -> 28:43, #6 -Counter in file 0 32:13 -> 32:42, (#8 - #9) -Counter in file 0 32:42 -> 32:43, #7 -Counter in file 0 33:10 -> 33:11, #2 -Counter in file 0 33:10 -> 33:11, #3 -Counter in file 0 34:6 -> 34:7, (#2 + #3) -Counter in file 0 35:5 -> 35:11, #4 -Counter in file 0 36:1 -> 36:2, ((#5 + (#6 + #7)) + #4) -Counter in file 0 5:8 -> 5:20, #1 -Counter in file 0 6:9 -> 6:16, #2 -Counter in file 0 8:9 -> 8:15, (#1 - #2) -Counter in file 0 10:1 -> 10:2, (#2 + (#1 - #2)) -Emitting segments for file: ../coverage/try_error_result.rs -Combined regions: - 5:8 -> 5:20 (count=6) - 6:9 -> 6:16 (count=1) - 8:9 -> 8:15 (count=5) - 10:1 -> 10:2 (count=6) - 13:9 -> 14:23 (count=1) - 17:9 -> 17:10 (count=6) - 19:9 -> 19:14 (count=6) - 21:9 -> 25:26 (count=6) - 27:13 -> 27:41 (count=1) - 27:41 -> 27:42 (count=1) - 28:13 -> 28:42 (count=0) - 28:42 -> 28:43 (count=0) - 32:13 -> 32:42 (count=5) - 32:42 -> 32:43 (count=0) - 33:10 -> 33:11 (count=5) - 34:6 -> 34:7 (count=5) - 35:5 -> 35:11 (count=0) - 36:1 -> 36:2 (count=1) -Segment at 5:8 (count = 6), RegionEntry -Segment at 5:20 (count = 0), Skipped -Segment at 6:9 (count = 1), RegionEntry -Segment at 6:16 (count = 0), Skipped -Segment at 8:9 (count = 5), RegionEntry -Segment at 8:15 (count = 0), Skipped -Segment at 10:1 (count = 6), RegionEntry -Segment at 10:2 (count = 0), Skipped -Segment at 13:9 (count = 1), RegionEntry -Segment at 14:23 (count = 0), Skipped -Segment at 17:9 (count = 6), RegionEntry -Segment at 17:10 (count = 0), Skipped -Segment at 19:9 (count = 6), RegionEntry -Segment at 19:14 (count = 0), Skipped -Segment at 21:9 (count = 6), RegionEntry -Segment at 25:26 (count = 0), Skipped -Segment at 27:13 (count = 1), RegionEntry -Segment at 27:41 (count = 1), RegionEntry -Segment at 27:42 (count = 0), Skipped -Segment at 28:13 (count = 0), RegionEntry -Segment at 28:42 (count = 0), RegionEntry -Segment at 28:43 (count = 0), Skipped -Segment at 32:13 (count = 5), RegionEntry -Segment at 32:42 (count = 0), RegionEntry -Segment at 32:43 (count = 0), Skipped -Segment at 33:10 (count = 5), RegionEntry -Segment at 33:11 (count = 0), Skipped -Segment at 34:6 (count = 5), RegionEntry -Segment at 34:7 (count = 0), Skipped -Segment at 35:5 (count = 0), RegionEntry -Segment at 35:11 (count = 0), Skipped -Segment at 36:1 (count = 1), RegionEntry -Segment at 36:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while.txt deleted file mode 100644 index b0e881da7c8cb..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while.txt +++ /dev/null @@ -1,18 +0,0 @@ -Counter in file 0 2:9 -> 2:16, #1 -Counter in file 0 3:11 -> 3:20, (#1 + #2) -Counter in file 0 3:21 -> 4:6, #2 -Counter in file 0 5:1 -> 5:2, ((#1 + #2) - #2) -Emitting segments for file: ../coverage/while.rs -Combined regions: - 2:9 -> 2:16 (count=1) - 3:11 -> 3:20 (count=1) - 3:21 -> 4:6 (count=0) - 5:1 -> 5:2 (count=1) -Segment at 2:9 (count = 1), RegionEntry -Segment at 2:16 (count = 0), Skipped -Segment at 3:11 (count = 1), RegionEntry -Segment at 3:20 (count = 0), Skipped -Segment at 3:21 (count = 0), RegionEntry -Segment at 4:6 (count = 0), Skipped -Segment at 5:1 (count = 1), RegionEntry -Segment at 5:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while_early_ret.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while_early_ret.txt deleted file mode 100644 index f541baec50c0b..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while_early_ret.txt +++ /dev/null @@ -1,38 +0,0 @@ -Counter in file 0 5:9 -> 5:27, #1 -Counter in file 0 7:9 -> 9:10, (#1 + #2) -Counter in file 0 12:13 -> 14:14, ((#1 + #2) - #3) -Counter in file 0 18:21 -> 20:22, #6 -Counter in file 0 22:21 -> 22:27, #4 -Counter in file 0 26:21 -> 26:27, #5 -Counter in file 0 30:9 -> 32:10, #2 -Counter in file 0 35:5 -> 35:11, #3 -Counter in file 0 36:1 -> 36:2, ((#4 + #5) + #3) -Emitting segments for file: ../coverage/while_early_ret.rs -Combined regions: - 5:9 -> 5:27 (count=1) - 7:9 -> 9:10 (count=7) - 12:13 -> 14:14 (count=7) - 18:21 -> 20:22 (count=1) - 22:21 -> 22:27 (count=0) - 26:21 -> 26:27 (count=1) - 30:9 -> 32:10 (count=6) - 35:5 -> 35:11 (count=0) - 36:1 -> 36:2 (count=1) -Segment at 5:9 (count = 1), RegionEntry -Segment at 5:27 (count = 0), Skipped -Segment at 7:9 (count = 7), RegionEntry -Segment at 9:10 (count = 0), Skipped -Segment at 12:13 (count = 7), RegionEntry -Segment at 14:14 (count = 0), Skipped -Segment at 18:21 (count = 1), RegionEntry -Segment at 20:22 (count = 0), Skipped -Segment at 22:21 (count = 0), RegionEntry -Segment at 22:27 (count = 0), Skipped -Segment at 26:21 (count = 1), RegionEntry -Segment at 26:27 (count = 0), Skipped -Segment at 30:9 (count = 6), RegionEntry -Segment at 32:10 (count = 0), Skipped -Segment at 35:5 (count = 0), RegionEntry -Segment at 35:11 (count = 0), Skipped -Segment at 36:1 (count = 1), RegionEntry -Segment at 36:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/Makefile b/src/test/run-make-fulldeps/coverage-reports-deadcode/Makefile deleted file mode 100644 index b6a9acbf18b3c..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# needs-profiler-support -# ignore-msvc -# ignore-windows-gnu - -# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works -# properly. Since we only have GCC on the CI ignore the test for now. - -# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 -LINK_DEAD_CODE=yes - --include ../coverage-reports-base/Makefile - -# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and -# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. -# See ../coverage/coverage_tools.mk for more information. diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.closure.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.closure.json deleted file mode 100644 index bff55300b3ca3..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.closure.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/closure.rs", - "summary": { - "functions": { - "count": 5, - "covered": 3, - "percent": 60 - }, - "instantiations": { - "count": 5, - "covered": 3, - "percent": 60 - }, - "lines": { - "count": 91, - "covered": 77, - "percent": 84.61538461538461 - }, - "regions": { - "count": 25, - "covered": 13, - "notcovered": 12, - "percent": 52 - } - } - } - ], - "totals": { - "functions": { - "count": 5, - "covered": 3, - "percent": 60 - }, - "instantiations": { - "count": 5, - "covered": 3, - "percent": 60 - }, - "lines": { - "count": 91, - "covered": 77, - "percent": 84.61538461538461 - }, - "regions": { - "count": 25, - "covered": 13, - "notcovered": 12, - "percent": 52 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if.json deleted file mode 100644 index 84dcc251f3f4b..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/if.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 19, - "covered": 19, - "percent": 100 - }, - "regions": { - "count": 5, - "covered": 4, - "notcovered": 1, - "percent": 80 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 19, - "covered": 19, - "percent": 100 - }, - "regions": { - "count": 5, - "covered": 4, - "notcovered": 1, - "percent": 80 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if_else.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if_else.json deleted file mode 100644 index 36f81ceae19bf..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if_else.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/if_else.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 28, - "covered": 19, - "percent": 67.85714285714286 - }, - "regions": { - "count": 7, - "covered": 5, - "notcovered": 2, - "percent": 71.42857142857143 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 28, - "covered": 19, - "percent": 67.85714285714286 - }, - "regions": { - "count": 7, - "covered": 5, - "notcovered": 2, - "percent": 71.42857142857143 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.nested_loops.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.nested_loops.json deleted file mode 100644 index 68163eb763619..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.nested_loops.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/nested_loops.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 21, - "covered": 16, - "percent": 76.19047619047619 - }, - "regions": { - "count": 18, - "covered": 14, - "notcovered": 4, - "percent": 77.77777777777779 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 21, - "covered": 16, - "percent": 76.19047619047619 - }, - "regions": { - "count": 18, - "covered": 14, - "notcovered": 4, - "percent": 77.77777777777779 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.partial_eq.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.partial_eq.json deleted file mode 100644 index bc0d0088041a8..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.partial_eq.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/partial_eq.rs", - "summary": { - "functions": { - "count": 5, - "covered": 5, - "percent": 100 - }, - "instantiations": { - "count": 8, - "covered": 5, - "percent": 62.5 - }, - "lines": { - "count": 15, - "covered": 15, - "percent": 100 - }, - "regions": { - "count": 6, - "covered": 6, - "notcovered": 0, - "percent": 100 - } - } - } - ], - "totals": { - "functions": { - "count": 5, - "covered": 5, - "percent": 100 - }, - "instantiations": { - "count": 8, - "covered": 5, - "percent": 62.5 - }, - "lines": { - "count": 15, - "covered": 15, - "percent": 100 - }, - "regions": { - "count": 6, - "covered": 6, - "notcovered": 0, - "percent": 100 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.while_early_ret.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.while_early_ret.json deleted file mode 100644 index ad43f5d992630..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.while_early_ret.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "../coverage/while_early_ret.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 17, - "covered": 15, - "percent": 88.23529411764706 - }, - "regions": { - "count": 9, - "covered": 7, - "notcovered": 2, - "percent": 77.77777777777779 - } - } - } - ], - "totals": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 17, - "covered": 15, - "percent": 88.23529411764706 - }, - "regions": { - "count": 9, - "covered": 7, - "notcovered": 2, - "percent": 77.77777777777779 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.conditions.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.conditions.txt deleted file mode 100644 index 173ff4aa4c481..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.conditions.txt +++ /dev/null @@ -1,69 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| |fn main() { - 4| 1| let mut countdown = 0; - 5| 1| if true { - 6| 1| countdown = 10; - 7| 1| } - 8| | - 9| | const B: u32 = 100; - 10| 1| let x = if countdown > 7 { - 11| 1| countdown -= 4; - 12| 1| B - 13| 0| } else if countdown > 2 { - 14| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 15| 0| countdown = 0; - 16| 0| } - 17| 0| countdown -= 5; - 18| 0| countdown - 19| | } else { - 20| 0| return; - 21| | }; - 22| | - 23| 1| let mut countdown = 0; - 24| 1| if true { - 25| 1| countdown = 10; - 26| 1| } - 27| | - 28| 1| if countdown > 7 { - 29| 1| countdown -= 4; - 30| 0| } else if countdown > 2 { - 31| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 32| 0| countdown = 0; - 33| 0| } - 34| 0| countdown -= 5; - 35| | } else { - 36| 0| return; - 37| | } - 38| | - 39| 1| let mut countdown = 0; - 40| 1| if true { - 41| 1| countdown = 1; - 42| 1| } - 43| | - 44| 1| let z = if countdown > 7 { - ^0 - 45| 0| countdown -= 4; - 46| 1| } else if countdown > 2 { - 47| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 48| 0| countdown = 0; - 49| 0| } - 50| 0| countdown -= 5; - 51| | } else { - 52| 1| let should_be_reachable = countdown; - 53| 1| println!("reached"); - 54| 1| return; - 55| | }; - 56| | - 57| 0| let w = if countdown > 7 { - 58| 0| countdown -= 4; - 59| 0| } else if countdown > 2 { - 60| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 61| 0| countdown = 0; - 62| 0| } - 63| 0| countdown -= 5; - 64| | } else { - 65| 0| return; - 66| | }; - 67| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.drop_trait.txt deleted file mode 100644 index 72aa020ca1691..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.drop_trait.txt +++ /dev/null @@ -1,34 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| |// expect-exit-status-1 - 3| | - 4| |struct Firework { - 5| | strength: i32, - 6| |} - 7| | - 8| |impl Drop for Firework { - 9| 2| fn drop(&mut self) { - 10| 2| println!("BOOM times {}!!!", self.strength); - 11| 2| } - 12| |} - 13| | - 14| |fn main() -> Result<(),u8> { - 15| 1| let _firecracker = Firework { strength: 1 }; - 16| 1| - 17| 1| let _tnt = Firework { strength: 100 }; - 18| | - 19| 1| if true { - 20| 1| println!("Exiting with error..."); - 21| 1| return Err(1); - 22| | } - 23| | - 24| | let _ = Firework { strength: 1000 }; - 25| | - 26| | Ok(()) - 27| 1|} - 28| | - 29| |// Expected program output: - 30| |// Exiting with error... - 31| |// BOOM times 100!!! - 32| |// BOOM times 1!!! - 33| |// Error: 1 - diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.generics.txt deleted file mode 100644 index 86199d7476302..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.generics.txt +++ /dev/null @@ -1,67 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| |// expect-exit-status-1 - 3| | - 4| |struct Firework where T: Copy + std::fmt::Display { - 5| | strength: T, - 6| |} - 7| | - 8| |impl Firework where T: Copy + std::fmt::Display { - 9| | #[inline(always)] - 10| 3| fn set_strength(&mut self, new_strength: T) { - 11| 3| self.strength = new_strength; - 12| 3| } - ------------------ - | >::set_strength: - | 10| 2| fn set_strength(&mut self, new_strength: T) { - | 11| 2| self.strength = new_strength; - | 12| 2| } - ------------------ - | >::set_strength: - | 10| 1| fn set_strength(&mut self, new_strength: T) { - | 11| 1| self.strength = new_strength; - | 12| 1| } - ------------------ - 13| |} - 14| | - 15| |impl Drop for Firework where T: Copy + std::fmt::Display { - 16| | #[inline(always)] - 17| 2| fn drop(&mut self) { - 18| 2| println!("BOOM times {}!!!", self.strength); - 19| 2| } - ------------------ - | as core::ops::drop::Drop>::drop: - | 17| 1| fn drop(&mut self) { - | 18| 1| println!("BOOM times {}!!!", self.strength); - | 19| 1| } - ------------------ - | as core::ops::drop::Drop>::drop: - | 17| 1| fn drop(&mut self) { - | 18| 1| println!("BOOM times {}!!!", self.strength); - | 19| 1| } - ------------------ - 20| |} - 21| | - 22| |fn main() -> Result<(),u8> { - 23| 1| let mut firecracker = Firework { strength: 1 }; - 24| 1| firecracker.set_strength(2); - 25| 1| - 26| 1| let mut tnt = Firework { strength: 100.1 }; - 27| 1| tnt.set_strength(200.1); - 28| 1| tnt.set_strength(300.3); - 29| | - 30| 1| if true { - 31| 1| println!("Exiting with error..."); - 32| 1| return Err(1); - 33| | } - 34| | - 35| | let _ = Firework { strength: 1000 }; - 36| | - 37| | Ok(()) - 38| 1|} - 39| | - 40| |// Expected program output: - 41| |// Exiting with error... - 42| |// BOOM times 100!!! - 43| |// BOOM times 1!!! - 44| |// Error: 1 - diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if.txt deleted file mode 100644 index 85e6440ab3729..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if.txt +++ /dev/null @@ -1,30 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| |fn main() { - 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| | // dependent conditions. - 7| | let - 8| 1| is_true - 9| 1| = - 10| 1| std::env::args().len() - 11| 1| == - 12| 1| 1 - 13| 1| ; - 14| 1| let - 15| 1| mut - 16| 1| countdown - 17| 1| = - 18| 1| 0 - 19| | ; - 20| | if - 21| 1| is_true - 22| 1| { - 23| 1| countdown - 24| 1| = - 25| 1| 10 - 26| 1| ; - 27| 1| } - ^0 - 28| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.lazy_boolean.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.lazy_boolean.txt deleted file mode 100644 index 1b503033911c5..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.lazy_boolean.txt +++ /dev/null @@ -1,65 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| |fn main() { - 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| | // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let (mut a, mut b, mut c) = (0, 0, 0); - 10| 1| if is_true { - 11| 1| a = 1; - 12| 1| b = 10; - 13| 1| c = 100; - 14| 1| } - ^0 - 15| | let - 16| 1| somebool - 17| | = - 18| 1| a < b - 19| | || - 20| 1| b < c - ^0 - 21| | ; - 22| | let - 23| 1| somebool - 24| | = - 25| 1| b < a - 26| | || - 27| 1| b < c - 28| | ; - 29| 1| let somebool = a < b && b < c; - 30| 1| let somebool = b < a && b < c; - ^0 - 31| | - 32| | if - 33| 1| ! - 34| 1| is_true - 35| 0| { - 36| 0| a = 2 - 37| 0| ; - 38| 1| } - 39| | - 40| | if - 41| 1| is_true - 42| 1| { - 43| 1| b = 30 - 44| 1| ; - 45| 1| } - 46| | else - 47| 0| { - 48| 0| c = 400 - 49| 0| ; - 50| 0| } - 51| | - 52| 1| if !is_true { - 53| 0| a = 2; - 54| 1| } - 55| | - 56| 1| if is_true { - 57| 1| b = 30; - 58| 1| } else { - 59| 0| c = 400; - 60| 0| } - 61| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.loop_break_value.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.loop_break_value.txt deleted file mode 100644 index b0d668c6d76da..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.loop_break_value.txt +++ /dev/null @@ -1,14 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| | - 3| 1|fn main() { - 4| 1| let result - 5| 1| = - 6| 1| loop - 7| 1| { - 8| 1| break - 9| 1| 10 - 10| 1| ; - 11| 1| } - 12| 1| ; - 13| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.loops_branches.txt deleted file mode 100644 index 3a969a6b89869..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.loops_branches.txt +++ /dev/null @@ -1,38 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| | - 3| |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the - 4| |// structure of this `fmt` function. - 5| | - 6| |struct DebugTest; - 7| | - 8| |impl std::fmt::Debug for DebugTest { - 9| | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - 10| 1| if true { - 11| 1| if false { - 12| | while true { - 13| | } - 14| 1| } - 15| 1| write!(f, "error")?; - ^0 - 16| | } else { - 17| 1| } - 18| 1| Ok(()) - 19| 1| } - 20| |} - 21| | - 22| 1|fn main() { - 23| 1| let debug_test = DebugTest; - 24| 1| println!("{:?}", debug_test); - 25| 1|} - 26| | - 27| |/* - 28| | - 29| |This is the error message generated, before the issue was fixed: - 30| | - 31| |error: internal compiler error: compiler/rustc_mir/src/transform/coverage/mod.rs:374:42: - 32| |Error processing: DefId(0:6 ~ bug_incomplete_cov_graph_traversal_simplified[317d]::{impl#0}::fmt): - 33| |Error { message: "`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: - 34| |[bcb6, bcb7, bcb9]" } - 35| | - 36| |*/ - diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.nested_loops.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.nested_loops.txt deleted file mode 100644 index c9f373bf6a7c0..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.nested_loops.txt +++ /dev/null @@ -1,26 +0,0 @@ - 1| |fn main() { - 2| 1| let is_true = std::env::args().len() == 1; - 3| 1| let mut countdown = 10; - 4| | - 5| 1| 'outer: while countdown > 0 { - 6| 1| let mut a = 100; - 7| 1| let mut b = 100; - 8| 3| for _ in 0..50 { - 9| 3| if a < 30 { - 10| 0| break; - 11| | } - 12| 3| a -= 5; - 13| 3| b -= 5; - 14| 3| if b < 90 { - 15| 1| a -= 10; - 16| 1| if is_true { - 17| 1| break 'outer; - 18| | } else { - 19| 0| a -= 2; - 20| 0| } - 21| 2| } - 22| 2| } - 23| 0| countdown -= 1; - 24| 0| } - 25| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.partial_eq.txt deleted file mode 100644 index d16a0a9c4c8c4..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.partial_eq.txt +++ /dev/null @@ -1,111 +0,0 @@ - 1| |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the - 2| |// structure of this test. - 3| | - 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] - ^1 ^1 - ------------------ - | Unexecuted instantiation: ::gt - ------------------ - | Unexecuted instantiation: ::le - ------------------ - | Unexecuted instantiation: ::ge - ------------------ - | ::lt: - | 4| 1|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] - ------------------ - 5| |pub struct Version { - 6| | major: usize, - 7| 1| minor: usize, - 8| | patch: usize, - 9| |} - 10| | - 11| |impl Version { - 12| | pub fn new(major: usize, minor: usize, patch: usize) -> Self { - 13| 2| Self { - 14| 2| major, - 15| 2| minor, - 16| 2| patch, - 17| 2| } - 18| 2| } - 19| |} - 20| | - 21| 1|fn main() { - 22| 1| let version_3_2_1 = Version::new(3, 2, 1); - 23| 1| let version_3_3_0 = Version::new(3, 3, 0); - 24| 1| - 25| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); - 26| 1|} - 27| | - 28| |/* - 29| | - 30| |This test verifies a bug was fixed that otherwise generated this error: - 31| | - 32| |thread 'rustc' panicked at 'No counters provided the source_hash for function: - 33| | Instance { - 34| | def: Item(WithOptConstParam { - 35| | did: DefId(0:101 ~ autocfg[c44a]::version::{impl#2}::partial_cmp), - 36| | const_param_did: None - 37| | }), - 38| | substs: [] - 39| | }' - 40| |The `PartialOrd` derived by `Version` happened to generate a MIR that generated coverage - 41| |without a code region associated with any `Counter`. Code regions were associated with at least - 42| |one expression, which is allowed, but the `function_source_hash` was only passed to the codegen - 43| |(coverage mapgen) phase from a `Counter`s code region. A new method was added to pass the - 44| |`function_source_hash` without a code region, if necessary. - 45| | - 46| |*/ - 47| | - 48| |// FIXME(richkadel): It may be worth investigating why the coverage report for this test produces - 49| |// the following results: - 50| | - 51| |/* - 52| | - 53| |1. Why are their two counts below different characters (first and last) of `PartialOrd`, on line 17? - 54| | - 55| |2. Line 17 is counted twice, but the `::lt` instance shows a line count of 1? Is there a missing - 56| | line count with a different instance? Or was it really only called once? - 57| | - 58| |3. Line 20 shows another line count (of 1) for a line within a `struct` declaration (on only one of - 59| | its 3 fields). I doubt the specific field (`minor`) is relevant, but rather I suspect there's a - 60| | problem computing the file position here, for some reason. - 61| | - 62| | - 63| | 16| | - 64| | 17| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] - 65| | ^1 ^1 - 66| |------------------ - 67| ||Unexecuted instantiation: ::gt - 68| |------------------ - 69| ||Unexecuted instantiation: ::le - 70| |------------------ - 71| ||Unexecuted instantiation: ::ge - 72| |------------------ - 73| ||::lt: - 74| || 17| 1|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] - 75| |------------------ - 76| | 18| |pub struct Version { - 77| | 19| | major: usize, - 78| | 20| 1| minor: usize, - 79| | 21| | patch: usize, - 80| | 22| |} - 81| | 23| | - 82| | 24| |impl Version { - 83| | 25| | pub fn new(major: usize, minor: usize, patch: usize) -> Self { - 84| | 26| 2| Version { - 85| | 27| 2| major, - 86| | 28| 2| minor, - 87| | 29| 2| patch, - 88| | 30| 2| } - 89| | 31| 2| } - 90| | 32| |} - 91| | 33| | - 92| | 34| 1|fn main() { - 93| | 35| 1| let version_3_2_1 = Version::new(3, 2, 1); - 94| | 36| 1| let version_3_3_0 = Version::new(3, 3, 0); - 95| | 37| 1| - 96| | 38| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version - 97| |_3_3_0); - 98| | 39| 1|} - 99| |*/ - diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.tight_inf_loop.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.tight_inf_loop.txt deleted file mode 100644 index e02eac03a6b15..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.tight_inf_loop.txt +++ /dev/null @@ -1,6 +0,0 @@ - 1| |fn main() { - 2| 1| if false { - 3| | loop {} - 4| | } - 5| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.while.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.while.txt deleted file mode 100644 index 194325b6b9eca..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.while.txt +++ /dev/null @@ -1,6 +0,0 @@ - 1| |fn main() { - 2| 1| let num = 9; - 3| 1| while num >= 10 { - 4| 0| } - 5| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.while_early_ret.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.while_early_ret.txt deleted file mode 100644 index 26041136d2f4c..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.while_early_ret.txt +++ /dev/null @@ -1,48 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| |// expect-exit-status-1 - 3| | - 4| |fn main() -> Result<(),u8> { - 5| 1| let mut countdown = 10; - 6| | while - 7| 7| countdown - 8| 7| > - 9| 7| 0 - 10| | { - 11| | if - 12| 7| countdown - 13| 7| < - 14| 7| 5 - 15| | { - 16| | return - 17| | if - 18| 1| countdown - 19| 1| > - 20| 1| 8 - 21| | { - 22| 0| Ok(()) - 23| | } - 24| | else - 25| | { - 26| 1| Err(1) - 27| | } - 28| | ; - 29| | } - 30| 6| countdown - 31| 6| -= - 32| 6| 1 - 33| | ; - 34| | } - 35| 0| Ok(()) - 36| 1|} - 37| | - 38| |// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and - 39| |// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux - 40| |// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program - 41| |// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical - 42| |// to the coverage test for early returns, but this is a limitation that should be fixed. - 43| |// - 44| |// FIXME(richkadel): Consider creating a new tests for coverage when calling `std::process::exit()`, - 45| |// move the `ISSUE` comment to that test, and implement a new test directive that supports skipping - 46| |// coverage tests when targeting specific platforms (at least skipping Windows, or MSVC if the - 47| |// problem exists on MSVC only). - diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.closure.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.closure.txt deleted file mode 100644 index fb797796e4e7d..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.closure.txt +++ /dev/null @@ -1,94 +0,0 @@ -Counter in file 0 20:21 -> 20:38, #1 -Counter in file 0 21:20 -> 21:28, (#1 + 0) -Counter in file 0 21:29 -> 23:18, #2 -Counter in file 0 23:18 -> 23:19, (#1 - #2) -Counter in file 0 24:17 -> 25:14, (#2 + (#1 - #2)) -Counter in file 0 3:11 -> 18:13, #1 -Counter in file 0 25:14 -> 33:9, (#1 + 0) -Counter in file 0 40:6 -> 60:13, (#1 + 0) -Counter in file 0 67:14 -> 75:9, (#1 + 0) -Counter in file 0 82:6 -> 93:2, (#1 + 0) -Counter in file 0 77:13 -> 77:30, #1 -Counter in file 0 78:12 -> 78:20, (#1 + 0) -Counter in file 0 78:21 -> 80:10, #2 -Counter in file 0 80:10 -> 80:11, (#1 - #2) -Counter in file 0 81:9 -> 82:6, (#2 + (#1 - #2)) -Counter in file 0 62:21 -> 62:38, #1 -Counter in file 0 63:20 -> 63:28, (#1 + 0) -Counter in file 0 63:29 -> 65:18, #2 -Counter in file 0 65:18 -> 65:19, (#1 - #2) -Counter in file 0 66:17 -> 67:14, (#2 + (#1 - #2)) -Counter in file 0 35:13 -> 35:30, #1 -Counter in file 0 36:12 -> 36:20, (#1 + 0) -Counter in file 0 36:21 -> 38:10, #2 -Counter in file 0 38:10 -> 38:11, (#1 - #2) -Counter in file 0 39:9 -> 40:6, (#2 + (#1 - #2)) -Emitting segments for file: ../coverage/closure.rs -Combined regions: - 3:11 -> 18:13 (count=1) - 20:21 -> 20:38 (count=0) - 21:20 -> 21:28 (count=0) - 21:29 -> 23:18 (count=0) - 23:18 -> 23:19 (count=0) - 24:17 -> 25:14 (count=0) - 25:14 -> 33:9 (count=1) - 35:13 -> 35:30 (count=0) - 36:12 -> 36:20 (count=0) - 36:21 -> 38:10 (count=0) - 38:10 -> 38:11 (count=0) - 39:9 -> 40:6 (count=0) - 40:6 -> 60:13 (count=1) - 62:21 -> 62:38 (count=1) - 63:20 -> 63:28 (count=1) - 63:29 -> 65:18 (count=0) - 65:18 -> 65:19 (count=1) - 66:17 -> 67:14 (count=1) - 67:14 -> 75:9 (count=1) - 77:13 -> 77:30 (count=1) - 78:12 -> 78:20 (count=1) - 78:21 -> 80:10 (count=0) - 80:10 -> 80:11 (count=1) - 81:9 -> 82:6 (count=1) - 82:6 -> 93:2 (count=1) -Segment at 3:11 (count = 1), RegionEntry -Segment at 18:13 (count = 0), Skipped -Segment at 20:21 (count = 0), RegionEntry -Segment at 20:38 (count = 0), Skipped -Segment at 21:20 (count = 0), RegionEntry -Segment at 21:28 (count = 0), Skipped -Segment at 21:29 (count = 0), RegionEntry -Segment at 23:18 (count = 0), RegionEntry -Segment at 23:19 (count = 0), Skipped -Segment at 24:17 (count = 0), RegionEntry -Segment at 25:14 (count = 1), RegionEntry -Segment at 33:9 (count = 0), Skipped -Segment at 35:13 (count = 0), RegionEntry -Segment at 35:30 (count = 0), Skipped -Segment at 36:12 (count = 0), RegionEntry -Segment at 36:20 (count = 0), Skipped -Segment at 36:21 (count = 0), RegionEntry -Segment at 38:10 (count = 0), RegionEntry -Segment at 38:11 (count = 0), Skipped -Segment at 39:9 (count = 0), RegionEntry -Segment at 40:6 (count = 1), RegionEntry -Segment at 60:13 (count = 0), Skipped -Segment at 62:21 (count = 1), RegionEntry -Segment at 62:38 (count = 0), Skipped -Segment at 63:20 (count = 1), RegionEntry -Segment at 63:28 (count = 0), Skipped -Segment at 63:29 (count = 0), RegionEntry -Segment at 65:18 (count = 1), RegionEntry -Segment at 65:19 (count = 0), Skipped -Segment at 66:17 (count = 1), RegionEntry -Segment at 67:14 (count = 1), RegionEntry -Segment at 75:9 (count = 0), Skipped -Segment at 77:13 (count = 1), RegionEntry -Segment at 77:30 (count = 0), Skipped -Segment at 78:12 (count = 1), RegionEntry -Segment at 78:20 (count = 0), Skipped -Segment at 78:21 (count = 0), RegionEntry -Segment at 80:10 (count = 1), RegionEntry -Segment at 80:11 (count = 0), Skipped -Segment at 81:9 (count = 1), RegionEntry -Segment at 82:6 (count = 1), RegionEntry -Segment at 93:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.conditions.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.conditions.txt deleted file mode 100644 index d48cd8074bebb..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.conditions.txt +++ /dev/null @@ -1,238 +0,0 @@ -Counter in file 0 4:9 -> 4:26, #1 -Counter in file 0 5:8 -> 5:12, (#1 + 0) -Counter in file 0 5:13 -> 7:6, #2 -Counter in file 0 10:9 -> 10:10, (#4 + #11) -Counter in file 0 10:16 -> 10:29, (#2 + 0) -Counter in file 0 11:9 -> 12:10, #4 -Counter in file 0 13:15 -> 13:28, ((#2 + 0) - #3) -Counter in file 0 14:12 -> 14:25, #5 -Counter in file 0 14:29 -> 14:42, (#5 - #13) -Counter in file 0 14:42 -> 14:43, (#13 + #14) -Counter in file 0 14:42 -> 14:43, ((#5 - #13) - #14) -Counter in file 0 14:46 -> 14:60, #21 -Counter in file 0 14:60 -> 14:61, (#17 + #18) -Counter in file 0 14:60 -> 14:61, (#21 - #18) -Counter in file 0 14:61 -> 16:10, #22 -Counter in file 0 16:10 -> 16:11, #23 -Counter in file 0 17:9 -> 18:18, #11 -Counter in file 0 20:9 -> 20:15, (((#2 + 0) - #3) - #5) -Counter in file 0 23:9 -> 23:26, ((#4 + #11) + 0) -Counter in file 0 24:8 -> 24:12, ((#4 + #11) + 0) -Counter in file 0 24:13 -> 26:6, #12 -Counter in file 0 28:8 -> 28:21, (#12 + 0) -Counter in file 0 29:9 -> 29:23, #16 -Counter in file 0 30:15 -> 30:28, ((#12 + 0) - #15) -Counter in file 0 31:12 -> 31:25, (((#12 + 0) - #15) - #8) -Counter in file 0 31:29 -> 31:42, ((((#12 + 0) - #15) - #8) - #24) -Counter in file 0 31:42 -> 31:43, (((((#12 + 0) - #15) - #8) - #24) - #25) -Counter in file 0 31:42 -> 31:43, (#24 + #25) -Counter in file 0 31:46 -> 31:60, #32 -Counter in file 0 31:60 -> 31:61, (#28 + #29) -Counter in file 0 31:60 -> 31:61, (#32 - #29) -Counter in file 0 31:61 -> 33:10, #33 -Counter in file 0 33:10 -> 33:11, #34 -Counter in file 0 34:9 -> 34:23, #19 -Counter in file 0 36:9 -> 36:15, #8 -Counter in file 0 39:9 -> 39:26, (#16 + #19) -Counter in file 0 40:8 -> 40:12, ((#16 + #19) + 0) -Counter in file 0 40:13 -> 42:6, #20 -Counter in file 0 44:9 -> 44:10, (#27 + #30) -Counter in file 0 44:16 -> 44:29, (#20 + 0) -Counter in file 0 45:9 -> 45:23, #27 -Counter in file 0 46:15 -> 46:28, ((#20 + 0) - #26) -Counter in file 0 47:12 -> 47:25, (((#20 + 0) - #26) - #7) -Counter in file 0 47:29 -> 47:42, ((((#20 + 0) - #26) - #7) - #35) -Counter in file 0 47:42 -> 47:43, (#35 + #36) -Counter in file 0 47:42 -> 47:43, (((((#20 + 0) - #26) - #7) - #35) - #36) -Counter in file 0 47:46 -> 47:60, #41 -Counter in file 0 47:60 -> 47:61, (#37 + #38) -Counter in file 0 47:60 -> 47:61, (#41 - #38) -Counter in file 0 47:61 -> 49:10, #42 -Counter in file 0 49:10 -> 49:11, #43 -Counter in file 0 50:9 -> 50:23, #30 -Counter in file 0 52:13 -> 54:15, #7 -Counter in file 0 57:9 -> 57:10, (#9 + #10) -Counter in file 0 57:16 -> 57:29, ((#27 + #30) + 0) -Counter in file 0 58:9 -> 58:23, #9 -Counter in file 0 59:15 -> 59:28, ((#27 + #30) - #31) -Counter in file 0 60:12 -> 60:25, (((#27 + #30) - #31) - #6) -Counter in file 0 60:29 -> 60:42, ((((#27 + #30) - #31) - #6) - #39) -Counter in file 0 60:42 -> 60:43, (#39 + #40) -Counter in file 0 60:42 -> 60:43, (((((#27 + #30) - #31) - #6) - #39) - #40) -Counter in file 0 60:46 -> 60:60, #46 -Counter in file 0 60:60 -> 60:61, (#46 - #45) -Counter in file 0 60:60 -> 60:61, (#44 + #45) -Counter in file 0 60:61 -> 62:10, #47 -Counter in file 0 62:10 -> 62:11, #48 -Counter in file 0 63:9 -> 63:23, #10 -Counter in file 0 65:9 -> 65:15, #6 -Counter in file 0 67:1 -> 67:2, ((#9 + #10) + (((#6 + #7) + #8) + (((#2 + 0) - #3) - #5))) -Emitting segments for file: ../coverage/conditions.rs -Combined regions: - 4:9 -> 4:26 (count=1) - 5:8 -> 5:12 (count=1) - 5:13 -> 7:6 (count=1) - 10:9 -> 10:10 (count=1) - 10:16 -> 10:29 (count=1) - 11:9 -> 12:10 (count=1) - 13:15 -> 13:28 (count=0) - 14:12 -> 14:25 (count=0) - 14:29 -> 14:42 (count=0) - 14:42 -> 14:43 (count=0) - 14:46 -> 14:60 (count=0) - 14:60 -> 14:61 (count=0) - 14:61 -> 16:10 (count=0) - 16:10 -> 16:11 (count=0) - 17:9 -> 18:18 (count=0) - 20:9 -> 20:15 (count=0) - 23:9 -> 23:26 (count=1) - 24:8 -> 24:12 (count=1) - 24:13 -> 26:6 (count=1) - 28:8 -> 28:21 (count=1) - 29:9 -> 29:23 (count=1) - 30:15 -> 30:28 (count=0) - 31:12 -> 31:25 (count=0) - 31:29 -> 31:42 (count=0) - 31:42 -> 31:43 (count=0) - 31:46 -> 31:60 (count=0) - 31:60 -> 31:61 (count=0) - 31:61 -> 33:10 (count=0) - 33:10 -> 33:11 (count=0) - 34:9 -> 34:23 (count=0) - 36:9 -> 36:15 (count=0) - 39:9 -> 39:26 (count=1) - 40:8 -> 40:12 (count=1) - 40:13 -> 42:6 (count=1) - 44:9 -> 44:10 (count=0) - 44:16 -> 44:29 (count=1) - 45:9 -> 45:23 (count=0) - 46:15 -> 46:28 (count=1) - 47:12 -> 47:25 (count=0) - 47:29 -> 47:42 (count=0) - 47:42 -> 47:43 (count=0) - 47:46 -> 47:60 (count=0) - 47:60 -> 47:61 (count=0) - 47:61 -> 49:10 (count=0) - 49:10 -> 49:11 (count=0) - 50:9 -> 50:23 (count=0) - 52:13 -> 54:15 (count=1) - 57:9 -> 57:10 (count=0) - 57:16 -> 57:29 (count=0) - 58:9 -> 58:23 (count=0) - 59:15 -> 59:28 (count=0) - 60:12 -> 60:25 (count=0) - 60:29 -> 60:42 (count=0) - 60:42 -> 60:43 (count=0) - 60:46 -> 60:60 (count=0) - 60:60 -> 60:61 (count=0) - 60:61 -> 62:10 (count=0) - 62:10 -> 62:11 (count=0) - 63:9 -> 63:23 (count=0) - 65:9 -> 65:15 (count=0) - 67:1 -> 67:2 (count=1) -Segment at 4:9 (count = 1), RegionEntry -Segment at 4:26 (count = 0), Skipped -Segment at 5:8 (count = 1), RegionEntry -Segment at 5:12 (count = 0), Skipped -Segment at 5:13 (count = 1), RegionEntry -Segment at 7:6 (count = 0), Skipped -Segment at 10:9 (count = 1), RegionEntry -Segment at 10:10 (count = 0), Skipped -Segment at 10:16 (count = 1), RegionEntry -Segment at 10:29 (count = 0), Skipped -Segment at 11:9 (count = 1), RegionEntry -Segment at 12:10 (count = 0), Skipped -Segment at 13:15 (count = 0), RegionEntry -Segment at 13:28 (count = 0), Skipped -Segment at 14:12 (count = 0), RegionEntry -Segment at 14:25 (count = 0), Skipped -Segment at 14:29 (count = 0), RegionEntry -Segment at 14:42 (count = 0), RegionEntry -Segment at 14:43 (count = 0), Skipped -Segment at 14:46 (count = 0), RegionEntry -Segment at 14:60 (count = 0), RegionEntry -Segment at 14:61 (count = 0), RegionEntry -Segment at 16:10 (count = 0), RegionEntry -Segment at 16:11 (count = 0), Skipped -Segment at 17:9 (count = 0), RegionEntry -Segment at 18:18 (count = 0), Skipped -Segment at 20:9 (count = 0), RegionEntry -Segment at 20:15 (count = 0), Skipped -Segment at 23:9 (count = 1), RegionEntry -Segment at 23:26 (count = 0), Skipped -Segment at 24:8 (count = 1), RegionEntry -Segment at 24:12 (count = 0), Skipped -Segment at 24:13 (count = 1), RegionEntry -Segment at 26:6 (count = 0), Skipped -Segment at 28:8 (count = 1), RegionEntry -Segment at 28:21 (count = 0), Skipped -Segment at 29:9 (count = 1), RegionEntry -Segment at 29:23 (count = 0), Skipped -Segment at 30:15 (count = 0), RegionEntry -Segment at 30:28 (count = 0), Skipped -Segment at 31:12 (count = 0), RegionEntry -Segment at 31:25 (count = 0), Skipped -Segment at 31:29 (count = 0), RegionEntry -Segment at 31:42 (count = 0), RegionEntry -Segment at 31:43 (count = 0), Skipped -Segment at 31:46 (count = 0), RegionEntry -Segment at 31:60 (count = 0), RegionEntry -Segment at 31:61 (count = 0), RegionEntry -Segment at 33:10 (count = 0), RegionEntry -Segment at 33:11 (count = 0), Skipped -Segment at 34:9 (count = 0), RegionEntry -Segment at 34:23 (count = 0), Skipped -Segment at 36:9 (count = 0), RegionEntry -Segment at 36:15 (count = 0), Skipped -Segment at 39:9 (count = 1), RegionEntry -Segment at 39:26 (count = 0), Skipped -Segment at 40:8 (count = 1), RegionEntry -Segment at 40:12 (count = 0), Skipped -Segment at 40:13 (count = 1), RegionEntry -Segment at 42:6 (count = 0), Skipped -Segment at 44:9 (count = 0), RegionEntry -Segment at 44:10 (count = 0), Skipped -Segment at 44:16 (count = 1), RegionEntry -Segment at 44:29 (count = 0), Skipped -Segment at 45:9 (count = 0), RegionEntry -Segment at 45:23 (count = 0), Skipped -Segment at 46:15 (count = 1), RegionEntry -Segment at 46:28 (count = 0), Skipped -Segment at 47:12 (count = 0), RegionEntry -Segment at 47:25 (count = 0), Skipped -Segment at 47:29 (count = 0), RegionEntry -Segment at 47:42 (count = 0), RegionEntry -Segment at 47:43 (count = 0), Skipped -Segment at 47:46 (count = 0), RegionEntry -Segment at 47:60 (count = 0), RegionEntry -Segment at 47:61 (count = 0), RegionEntry -Segment at 49:10 (count = 0), RegionEntry -Segment at 49:11 (count = 0), Skipped -Segment at 50:9 (count = 0), RegionEntry -Segment at 50:23 (count = 0), Skipped -Segment at 52:13 (count = 1), RegionEntry -Segment at 54:15 (count = 0), Skipped -Segment at 57:9 (count = 0), RegionEntry -Segment at 57:10 (count = 0), Skipped -Segment at 57:16 (count = 0), RegionEntry -Segment at 57:29 (count = 0), Skipped -Segment at 58:9 (count = 0), RegionEntry -Segment at 58:23 (count = 0), Skipped -Segment at 59:15 (count = 0), RegionEntry -Segment at 59:28 (count = 0), Skipped -Segment at 60:12 (count = 0), RegionEntry -Segment at 60:25 (count = 0), Skipped -Segment at 60:29 (count = 0), RegionEntry -Segment at 60:42 (count = 0), RegionEntry -Segment at 60:43 (count = 0), Skipped -Segment at 60:46 (count = 0), RegionEntry -Segment at 60:60 (count = 0), RegionEntry -Segment at 60:61 (count = 0), RegionEntry -Segment at 62:10 (count = 0), RegionEntry -Segment at 62:11 (count = 0), Skipped -Segment at 63:9 (count = 0), RegionEntry -Segment at 63:23 (count = 0), Skipped -Segment at 65:9 (count = 0), RegionEntry -Segment at 65:15 (count = 0), Skipped -Segment at 67:1 (count = 1), RegionEntry -Segment at 67:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.drop_trait.txt deleted file mode 100644 index 375025fe8bcc2..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.drop_trait.txt +++ /dev/null @@ -1,22 +0,0 @@ -Counter in file 0 9:24 -> 11:6, #1 -Counter in file 0 15:9 -> 17:42, #1 -Counter in file 0 19:8 -> 19:12, (#1 + 0) -Counter in file 0 20:9 -> 21:22, #2 -Counter in file 0 27:1 -> 27:2, (#2 + 0) -Emitting segments for file: ../coverage/drop_trait.rs -Combined regions: - 9:24 -> 11:6 (count=2) - 15:9 -> 17:42 (count=1) - 19:8 -> 19:12 (count=1) - 20:9 -> 21:22 (count=1) - 27:1 -> 27:2 (count=1) -Segment at 9:24 (count = 2), RegionEntry -Segment at 11:6 (count = 0), Skipped -Segment at 15:9 (count = 1), RegionEntry -Segment at 17:42 (count = 0), Skipped -Segment at 19:8 (count = 1), RegionEntry -Segment at 19:12 (count = 0), Skipped -Segment at 20:9 (count = 1), RegionEntry -Segment at 21:22 (count = 0), Skipped -Segment at 27:1 (count = 1), RegionEntry -Segment at 27:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.generics.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.generics.txt deleted file mode 100644 index 013a69ed3983a..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.generics.txt +++ /dev/null @@ -1,48 +0,0 @@ -Counter in file 0 17:24 -> 19:6, #1 -Counter in file 0 17:24 -> 19:6, #1 -Counter in file 0 23:9 -> 28:28, #1 -Counter in file 0 30:8 -> 30:12, (#1 + 0) -Counter in file 0 31:9 -> 32:22, #2 -Counter in file 0 38:1 -> 38:2, (#2 + 0) -Counter in file 0 10:49 -> 12:6, #1 -Counter in file 0 10:49 -> 12:6, #1 -Emitting segments for file: ../coverage/generics.rs -Combined regions: - 10:49 -> 12:6 (count=3) - 17:24 -> 19:6 (count=2) - 23:9 -> 28:28 (count=1) - 30:8 -> 30:12 (count=1) - 31:9 -> 32:22 (count=1) - 38:1 -> 38:2 (count=1) -Segment at 10:49 (count = 3), RegionEntry -Segment at 12:6 (count = 0), Skipped -Segment at 17:24 (count = 2), RegionEntry -Segment at 19:6 (count = 0), Skipped -Segment at 23:9 (count = 1), RegionEntry -Segment at 28:28 (count = 0), Skipped -Segment at 30:8 (count = 1), RegionEntry -Segment at 30:12 (count = 0), Skipped -Segment at 31:9 (count = 1), RegionEntry -Segment at 32:22 (count = 0), Skipped -Segment at 38:1 (count = 1), RegionEntry -Segment at 38:2 (count = 0), Skipped -Emitting segments for function: _RNvMCs4fqI2P2rA04_8genericsINtB2_8FireworkdE12set_strengthB2_ -Combined regions: - 10:49 -> 12:6 (count=2) -Segment at 10:49 (count = 2), RegionEntry -Segment at 12:6 (count = 0), Skipped -Emitting segments for function: _RNvMCs4fqI2P2rA04_8genericsINtB2_8FireworklE12set_strengthB2_ -Combined regions: - 10:49 -> 12:6 (count=1) -Segment at 10:49 (count = 1), RegionEntry -Segment at 12:6 (count = 0), Skipped -Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworklENtNtNtCs7f2nZg1zwMz_4core3ops4drop4Drop4dropB4_ -Combined regions: - 17:24 -> 19:6 (count=1) -Segment at 17:24 (count = 1), RegionEntry -Segment at 19:6 (count = 0), Skipped -Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworkdENtNtNtCs7f2nZg1zwMz_4core3ops4drop4Drop4dropB4_ -Combined regions: - 17:24 -> 19:6 (count=1) -Segment at 17:24 (count = 1), RegionEntry -Segment at 19:6 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.inner_items.txt deleted file mode 100644 index 65cd6481af4cc..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.inner_items.txt +++ /dev/null @@ -1,60 +0,0 @@ -Counter in file 0 19:13 -> 19:18, #1 -Counter in file 0 20:13 -> 20:14, #2 -Counter in file 0 20:17 -> 20:22, (#1 + 0) -Counter in file 0 21:9 -> 22:6, (#2 + 0) -Counter in file 0 7:9 -> 9:26, #1 -Counter in file 0 10:8 -> 10:15, (#1 + 0) -Counter in file 0 10:16 -> 12:6, #2 -Counter in file 0 12:6 -> 12:7, (#1 - #2) -Counter in file 0 48:8 -> 48:15, (#2 + (#1 - #2)) -Counter in file 0 48:16 -> 50:6, #3 -Counter in file 0 50:6 -> 50:7, ((#2 + (#1 - #2)) - #3) -Counter in file 0 52:9 -> 57:2, (#3 + ((#2 + (#1 - #2)) - #3)) -Counter in file 0 33:42 -> 36:10, #1 -Counter in file 0 41:37 -> 41:41, #1 -Counter in file 0 42:13 -> 43:10, #2 -Emitting segments for file: ../coverage/inner_items.rs -Combined regions: - 7:9 -> 9:26 (count=1) - 10:8 -> 10:15 (count=1) - 10:16 -> 12:6 (count=1) - 12:6 -> 12:7 (count=0) - 19:13 -> 19:18 (count=3) - 20:13 -> 20:14 (count=3) - 20:17 -> 20:22 (count=3) - 21:9 -> 22:6 (count=3) - 33:42 -> 36:10 (count=1) - 41:37 -> 41:41 (count=1) - 42:13 -> 43:10 (count=1) - 48:8 -> 48:15 (count=1) - 48:16 -> 50:6 (count=1) - 50:6 -> 50:7 (count=0) - 52:9 -> 57:2 (count=1) -Segment at 7:9 (count = 1), RegionEntry -Segment at 9:26 (count = 0), Skipped -Segment at 10:8 (count = 1), RegionEntry -Segment at 10:15 (count = 0), Skipped -Segment at 10:16 (count = 1), RegionEntry -Segment at 12:6 (count = 0), RegionEntry -Segment at 12:7 (count = 0), Skipped -Segment at 19:13 (count = 3), RegionEntry -Segment at 19:18 (count = 0), Skipped -Segment at 20:13 (count = 3), RegionEntry -Segment at 20:14 (count = 0), Skipped -Segment at 20:17 (count = 3), RegionEntry -Segment at 20:22 (count = 0), Skipped -Segment at 21:9 (count = 3), RegionEntry -Segment at 22:6 (count = 0), Skipped -Segment at 33:42 (count = 1), RegionEntry -Segment at 36:10 (count = 0), Skipped -Segment at 41:37 (count = 1), RegionEntry -Segment at 41:41 (count = 0), Skipped -Segment at 42:13 (count = 1), RegionEntry -Segment at 43:10 (count = 0), Skipped -Segment at 48:8 (count = 1), RegionEntry -Segment at 48:15 (count = 0), Skipped -Segment at 48:16 (count = 1), RegionEntry -Segment at 50:6 (count = 0), RegionEntry -Segment at 50:7 (count = 0), Skipped -Segment at 52:9 (count = 1), RegionEntry -Segment at 57:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.loop_break_value.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.loop_break_value.txt deleted file mode 100644 index a6144b8072ace..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.loop_break_value.txt +++ /dev/null @@ -1,6 +0,0 @@ -Counter in file 0 3:11 -> 13:2, #1 -Emitting segments for file: ../coverage/loop_break_value.rs -Combined regions: - 3:11 -> 13:2 (count=1) -Segment at 3:11 (count = 1), RegionEntry -Segment at 13:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.loops_branches.txt deleted file mode 100644 index d8af6998964cf..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.loops_branches.txt +++ /dev/null @@ -1,37 +0,0 @@ -Counter in file 0 10:12 -> 10:16, #1 -Counter in file 0 11:16 -> 11:21, #2 -Counter in file 0 14:14 -> 14:15, (#2 - #5) -Counter in file 0 15:13 -> 15:31, (0 + (#2 - #5)) -Counter in file 0 15:31 -> 15:32, #4 -Counter in file 0 17:10 -> 17:11, #3 -Counter in file 0 18:9 -> 18:15, (#3 + 0) -Counter in file 0 19:5 -> 19:6, (#4 + (#3 + 0)) -Counter in file 0 22:11 -> 25:2, #1 -Emitting segments for file: ../coverage/loops_branches.rs -Combined regions: - 10:12 -> 10:16 (count=1) - 11:16 -> 11:21 (count=1) - 14:14 -> 14:15 (count=1) - 15:13 -> 15:31 (count=1) - 15:31 -> 15:32 (count=0) - 17:10 -> 17:11 (count=1) - 18:9 -> 18:15 (count=1) - 19:5 -> 19:6 (count=1) - 22:11 -> 25:2 (count=1) -Segment at 10:12 (count = 1), RegionEntry -Segment at 10:16 (count = 0), Skipped -Segment at 11:16 (count = 1), RegionEntry -Segment at 11:21 (count = 0), Skipped -Segment at 14:14 (count = 1), RegionEntry -Segment at 14:15 (count = 0), Skipped -Segment at 15:13 (count = 1), RegionEntry -Segment at 15:31 (count = 0), RegionEntry -Segment at 15:32 (count = 0), Skipped -Segment at 17:10 (count = 1), RegionEntry -Segment at 17:11 (count = 0), Skipped -Segment at 18:9 (count = 1), RegionEntry -Segment at 18:15 (count = 0), Skipped -Segment at 19:5 (count = 1), RegionEntry -Segment at 19:6 (count = 0), Skipped -Segment at 22:11 (count = 1), RegionEntry -Segment at 25:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.nested_loops.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.nested_loops.txt deleted file mode 100644 index f503007353319..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.nested_loops.txt +++ /dev/null @@ -1,73 +0,0 @@ -Counter in file 0 2:9 -> 3:27, #1 -Counter in file 0 5:19 -> 5:32, (#1 + #2) -Counter in file 0 6:13 -> 7:24, ((#1 + #2) - #3) -Counter in file 0 8:13 -> 8:14, ((((#1 + #2) - #3) + (#5 + #6)) - #7) -Counter in file 0 8:18 -> 8:23, (((#1 + #2) - #3) + (#5 + #6)) -Counter in file 0 9:16 -> 9:22, (((((#1 + #2) - #3) + (#5 + #6)) - #7) + 0) -Counter in file 0 10:17 -> 10:22, #8 -Counter in file 0 12:13 -> 12:19, #9 -Counter in file 0 13:13 -> 13:19, #10 -Counter in file 0 14:16 -> 14:22, (#10 + 0) -Counter in file 0 15:17 -> 16:27, #11 -Counter in file 0 17:21 -> 17:33, #4 -Counter in file 0 19:21 -> 21:14, #5 -Counter in file 0 21:14 -> 21:15, #6 -Counter in file 0 22:10 -> 22:11, (#5 + #6) -Counter in file 0 23:9 -> 23:23, #2 -Counter in file 0 24:6 -> 24:7, #3 -Counter in file 0 25:1 -> 25:2, (#4 + #3) -Emitting segments for file: ../coverage/nested_loops.rs -Combined regions: - 2:9 -> 3:27 (count=1) - 5:19 -> 5:32 (count=1) - 6:13 -> 7:24 (count=1) - 8:13 -> 8:14 (count=3) - 8:18 -> 8:23 (count=3) - 9:16 -> 9:22 (count=3) - 10:17 -> 10:22 (count=0) - 12:13 -> 12:19 (count=3) - 13:13 -> 13:19 (count=3) - 14:16 -> 14:22 (count=3) - 15:17 -> 16:27 (count=1) - 17:21 -> 17:33 (count=1) - 19:21 -> 21:14 (count=0) - 21:14 -> 21:15 (count=2) - 22:10 -> 22:11 (count=2) - 23:9 -> 23:23 (count=0) - 24:6 -> 24:7 (count=0) - 25:1 -> 25:2 (count=1) -Segment at 2:9 (count = 1), RegionEntry -Segment at 3:27 (count = 0), Skipped -Segment at 5:19 (count = 1), RegionEntry -Segment at 5:32 (count = 0), Skipped -Segment at 6:13 (count = 1), RegionEntry -Segment at 7:24 (count = 0), Skipped -Segment at 8:13 (count = 3), RegionEntry -Segment at 8:14 (count = 0), Skipped -Segment at 8:18 (count = 3), RegionEntry -Segment at 8:23 (count = 0), Skipped -Segment at 9:16 (count = 3), RegionEntry -Segment at 9:22 (count = 0), Skipped -Segment at 10:17 (count = 0), RegionEntry -Segment at 10:22 (count = 0), Skipped -Segment at 12:13 (count = 3), RegionEntry -Segment at 12:19 (count = 0), Skipped -Segment at 13:13 (count = 3), RegionEntry -Segment at 13:19 (count = 0), Skipped -Segment at 14:16 (count = 3), RegionEntry -Segment at 14:22 (count = 0), Skipped -Segment at 15:17 (count = 1), RegionEntry -Segment at 16:27 (count = 0), Skipped -Segment at 17:21 (count = 1), RegionEntry -Segment at 17:33 (count = 0), Skipped -Segment at 19:21 (count = 0), RegionEntry -Segment at 21:14 (count = 2), RegionEntry -Segment at 21:15 (count = 0), Skipped -Segment at 22:10 (count = 2), RegionEntry -Segment at 22:11 (count = 0), Skipped -Segment at 23:9 (count = 0), RegionEntry -Segment at 23:23 (count = 0), Skipped -Segment at 24:6 (count = 0), RegionEntry -Segment at 24:7 (count = 0), Skipped -Segment at 25:1 (count = 1), RegionEntry -Segment at 25:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.partial_eq.txt deleted file mode 100644 index 2b9285202f97f..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.partial_eq.txt +++ /dev/null @@ -1,53 +0,0 @@ -Counter in file 0 4:32 -> 4:33, (#3 + (#1 + #2)) -Counter in file 0 4:48 -> 4:49, ((#1 + #2) + ((#3 + #4) + ((#5 + #6) + #7))) -Counter in file 0 21:11 -> 26:2, #1 -Counter in file 0 8:5 -> 8:17, #1 -Counter in file 0 8:5 -> 8:17, #1 -Counter in file 0 4:39 -> 4:40, #1 -Counter in file 0 4:48 -> 4:49, (#1 + 0) -Counter in file 0 4:39 -> 4:40, #1 -Counter in file 0 4:48 -> 4:49, (#1 + 0) -Counter in file 0 8:5 -> 8:17, #1 -Counter in file 0 4:32 -> 4:33, ((#4 + #5) + #6) -Counter in file 0 4:53 -> 4:54, (#1 + (#2 + (#3 + #4))) -Counter in file 0 13:9 -> 18:6, #1 -Counter in file 0 4:39 -> 4:40, #1 -Counter in file 0 4:48 -> 4:49, (#1 + 0) -Counter in file 0 7:5 -> 7:6, #1 -Counter in file 0 4:10 -> 4:15, #1 -Counter in file 0 4:35 -> 4:37, #1 -Counter in file 0 7:5 -> 7:6, #1 -Counter in file 0 7:5 -> 7:6, #1 -Counter in file 0 4:17 -> 4:22, #1 -Counter in file 0 8:5 -> 8:17, #1 -Counter in file 0 4:39 -> 4:40, #1 -Counter in file 0 4:48 -> 4:49, (#1 + 0) -Counter in file 0 7:5 -> 7:6, #1 -Emitting segments for file: ../coverage/partial_eq.rs -Combined regions: - 4:17 -> 4:22 (count=2) - 4:39 -> 4:40 (count=1) - 4:48 -> 4:49 (count=1) - 7:5 -> 7:6 (count=1) - 13:9 -> 18:6 (count=2) - 21:11 -> 26:2 (count=1) -Segment at 4:17 (count = 2), RegionEntry -Segment at 4:22 (count = 0), Skipped -Segment at 4:39 (count = 1), RegionEntry -Segment at 4:40 (count = 0), Skipped -Segment at 4:48 (count = 1), RegionEntry -Segment at 4:49 (count = 0), Skipped -Segment at 7:5 (count = 1), RegionEntry -Segment at 7:6 (count = 0), Skipped -Segment at 13:9 (count = 2), RegionEntry -Segment at 18:6 (count = 0), Skipped -Segment at 21:11 (count = 1), RegionEntry -Segment at 26:2 (count = 0), Skipped -Emitting segments for function: _RNvXs0_Cs4fqI2P2rA04_10partial_eqNtB5_7VersionNtNtCs7f2nZg1zwMz_4core3cmp10PartialOrd2ltB5_ -Combined regions: - 4:39 -> 4:40 (count=1) - 4:48 -> 4:49 (count=1) -Segment at 4:39 (count = 1), RegionEntry -Segment at 4:40 (count = 0), Skipped -Segment at 4:48 (count = 1), RegionEntry -Segment at 4:49 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.simple_loop.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.simple_loop.txt deleted file mode 100644 index 255173e5534d1..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.simple_loop.txt +++ /dev/null @@ -1,37 +0,0 @@ -Counter in file 0 7:9 -> 9:26, #1 -Counter in file 0 12:9 -> 12:16, (#1 + 0) -Counter in file 0 13:5 -> 18:6, #2 -Counter in file 0 18:6 -> 18:7, (#1 - #2) -Counter in file 0 23:13 -> 25:14, ((#2 + (#1 - #2)) + #3) -Counter in file 0 27:13 -> 27:18, #4 -Counter in file 0 30:9 -> 32:10, #3 -Counter in file 0 34:6 -> 34:7, (#2 + (#1 - #2)) -Counter in file 0 35:1 -> 35:2, (#4 + 0) -Emitting segments for file: ../coverage/simple_loop.rs -Combined regions: - 7:9 -> 9:26 (count=1) - 12:9 -> 12:16 (count=1) - 13:5 -> 18:6 (count=1) - 18:6 -> 18:7 (count=0) - 23:13 -> 25:14 (count=11) - 27:13 -> 27:18 (count=1) - 30:9 -> 32:10 (count=10) - 34:6 -> 34:7 (count=1) - 35:1 -> 35:2 (count=1) -Segment at 7:9 (count = 1), RegionEntry -Segment at 9:26 (count = 0), Skipped -Segment at 12:9 (count = 1), RegionEntry -Segment at 12:16 (count = 0), Skipped -Segment at 13:5 (count = 1), RegionEntry -Segment at 18:6 (count = 0), RegionEntry -Segment at 18:7 (count = 0), Skipped -Segment at 23:13 (count = 11), RegionEntry -Segment at 25:14 (count = 0), Skipped -Segment at 27:13 (count = 1), RegionEntry -Segment at 27:18 (count = 0), Skipped -Segment at 30:9 (count = 10), RegionEntry -Segment at 32:10 (count = 0), Skipped -Segment at 34:6 (count = 1), RegionEntry -Segment at 34:7 (count = 0), Skipped -Segment at 35:1 (count = 1), RegionEntry -Segment at 35:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.simple_match.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.simple_match.txt deleted file mode 100644 index 1682a379bc0ff..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.simple_match.txt +++ /dev/null @@ -1,57 +0,0 @@ -Counter in file 0 7:9 -> 9:26, #1 -Counter in file 0 10:8 -> 10:15, (#1 + 0) -Counter in file 0 10:16 -> 12:6, #2 -Counter in file 0 12:6 -> 12:7, (#1 - #2) -Counter in file 0 15:9 -> 15:10, (((#2 + (#1 - #2)) + (#3 + #4)) - #5) -Counter in file 0 17:9 -> 17:13, ((#2 + (#1 - #2)) + (#3 + #4)) -Counter in file 0 22:13 -> 22:22, ((((#2 + (#1 - #2)) + (#3 + #4)) - #5) + 0) -Counter in file 0 24:13 -> 24:14, #3 -Counter in file 0 26:17 -> 28:18, ((((#2 + (#1 - #2)) + (#3 + #4)) - #5) + 0) -Counter in file 0 28:18 -> 28:19, ((((#2 + (#1 - #2)) + (#3 + #4)) - #5) - #3) -Counter in file 0 30:13 -> 37:14, (#3 + 0) -Counter in file 0 40:13 -> 40:15, #4 -Counter in file 0 42:6 -> 42:7, (#2 + (#1 - #2)) -Counter in file 0 42:6 -> 42:7, (#3 + #4) -Counter in file 0 43:1 -> 43:2, #5 -Emitting segments for file: ../coverage/simple_match.rs -Combined regions: - 7:9 -> 9:26 (count=1) - 10:8 -> 10:15 (count=1) - 10:16 -> 12:6 (count=1) - 12:6 -> 12:7 (count=0) - 15:9 -> 15:10 (count=2) - 17:9 -> 17:13 (count=3) - 22:13 -> 22:22 (count=2) - 24:13 -> 24:14 (count=1) - 26:17 -> 28:18 (count=2) - 28:18 -> 28:19 (count=1) - 30:13 -> 37:14 (count=1) - 40:13 -> 40:15 (count=1) - 42:6 -> 42:7 (count=3) - 43:1 -> 43:2 (count=1) -Segment at 7:9 (count = 1), RegionEntry -Segment at 9:26 (count = 0), Skipped -Segment at 10:8 (count = 1), RegionEntry -Segment at 10:15 (count = 0), Skipped -Segment at 10:16 (count = 1), RegionEntry -Segment at 12:6 (count = 0), RegionEntry -Segment at 12:7 (count = 0), Skipped -Segment at 15:9 (count = 2), RegionEntry -Segment at 15:10 (count = 0), Skipped -Segment at 17:9 (count = 3), RegionEntry -Segment at 17:13 (count = 0), Skipped -Segment at 22:13 (count = 2), RegionEntry -Segment at 22:22 (count = 0), Skipped -Segment at 24:13 (count = 1), RegionEntry -Segment at 24:14 (count = 0), Skipped -Segment at 26:17 (count = 2), RegionEntry -Segment at 28:18 (count = 1), RegionEntry -Segment at 28:19 (count = 0), Skipped -Segment at 30:13 (count = 1), RegionEntry -Segment at 37:14 (count = 0), Skipped -Segment at 40:13 (count = 1), RegionEntry -Segment at 40:15 (count = 0), Skipped -Segment at 42:6 (count = 3), RegionEntry -Segment at 42:7 (count = 0), Skipped -Segment at 43:1 (count = 1), RegionEntry -Segment at 43:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.tight_inf_loop.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.tight_inf_loop.txt deleted file mode 100644 index 5887658fe67a2..0000000000000 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.tight_inf_loop.txt +++ /dev/null @@ -1,10 +0,0 @@ -Counter in file 0 2:8 -> 2:13, #1 -Counter in file 0 5:1 -> 5:2, (#1 - #2) -Emitting segments for file: ../coverage/tight_inf_loop.rs -Combined regions: - 2:8 -> 2:13 (count=1) - 5:1 -> 5:2 (count=1) -Segment at 2:8 (count = 1), RegionEntry -Segment at 2:13 (count = 0), Skipped -Segment at 5:1 (count = 1), RegionEntry -Segment at 5:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile similarity index 53% rename from src/test/run-make-fulldeps/coverage-reports-base/Makefile rename to src/test/run-make-fulldeps/coverage-reports/Makefile index 2dac8fc2225bf..302f09ae422bc 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -4,13 +4,9 @@ # FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works # properly. Since we only have GCC on the CI ignore the test for now. -# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and -# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. -# See ../coverage/coverage_tools.mk for more information. - -include ../coverage/coverage_tools.mk -BASEDIR=../coverage-reports-base +BASEDIR=../coverage-reports SOURCEDIR=../coverage # The `llvm-cov show` flag `--debug`, used to generate the `counters` output files, is only enabled @@ -26,6 +22,43 @@ ifeq ($(LLVM_COV_DEBUG), 1) DEBUG_FLAG=--debug endif +# FIXME(richkadel): I'm adding `--ignore-filename-regex=` line(s) for specific test(s) that produce +# `llvm-cov` results for multiple files (for example `uses_crate.rs` and `used_crate/mod.rs`) as a +# workaround for two problems causing tests to fail on Windows: +# +# 1. When multiple files appear in the `llvm-cov show` results, each file's coverage results can +# appear in different a different order. Whether this is random or, somehow, platform-specific, +# the Windows output flips the order of the files, compared to Linux. In the `uses_crate.rs` +# test, the only test-unique (interesting) results we care about are the results for only one +# of the two files, `mod/uses_crate.rs`, so the workaround is to ignore all but this one file. +# In the future, we may want a more sophisticated solution that splits apart `llvm-cov show` +# results into separate results files for each result (taking care not to create new file +# paths that might be too long for Windows MAX_PATH limits when creating these new sub-results, +# as well). +# 2. When multiple files appear in the `llvm-cov show` results, the results for each file are +# prefixed with their filename, including platform-specific path separators (`\` for Windows, +# and `/` everywhere else). This could be filtered or normalized of course, but by ignoring +# coverage results for all but one of the file, the filenames are no longer included anyway. +# If this changes (if/when we decide to support `llvm-cov show` results for multiple files), +# the file path separator differences may need to be addressed. +# +# Since this is only a workaround, I decided to implement the override by adding an option for +# each file to be ignored, using a `--ignore-filename-regex=` entry for each one, rather than +# implement some more sophisticated solution with a new custom test directive in the test file +# itself (similar to `expect-exit-status`) because that would add a lot of complexity and still +# be a workaround, with the same result, with no benefit. +# +# Yes these `--ignore-filename-regex=` options are included in all invocations of `llvm-cov show` +# for now, but it is effectively ignored for all tests that don't include this file anyway. +# +# Note that it's also possible the `_counters..txt` and `.json` files may order +# results from multiple files inconsistently, which might also have to be accomodated if and when +# we allow `llvm-cov` to produce results for multiple files. (The path separators appear to be +# normalized to `/` in those files, thankfully.) But since we are ignoring results for all but one +# file, this workaround addresses those potential issues as well. +LLVM_COV_IGNORE_FILES=\ + --ignore-filename-regex=uses_crate.rs + # When generating `expected_*` results (using `x.py test --bless`), the `--debug` flag is forced. # If assertions are disabled, the command will fail with an error, rather than attempt to generate # only partial results. @@ -34,7 +67,7 @@ DEBUG_FLAG=--debug endif ifeq ($(LLVM_VERSION_11_PLUS),true) -all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) +all: $(patsubst $(SOURCEDIR)/lib/%.rs,%,$(wildcard $(SOURCEDIR)/lib/*.rs)) $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) else $(info Rust option `-Z instrument-coverage` requires LLVM 11 or higher. Test skipped.) all: @@ -51,11 +84,17 @@ endif -include clear_expected_if_blessed +%: $(SOURCEDIR)/lib/%.rs + # Compile the test library with coverage instrumentation + $(RUSTC) $(SOURCEDIR)/lib/$@.rs \ + $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/lib/$@.rs && echo "--edition=2018" ) \ + --crate-type rlib -Zinstrument-coverage + %: $(SOURCEDIR)/%.rs - # Compile the test program with coverage instrumentation and generate relevant MIR. + # Compile the test program with coverage instrumentation $(RUSTC) $(SOURCEDIR)/$@.rs \ - -Zinstrument-coverage \ - -Clink-dead-code=$(LINK_DEAD_CODE) + $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && echo "--edition=2018" ) \ + -L "$(TMPDIR)" -Zinstrument-coverage # Run it in order to generate some profiling data, # with `LLVM_PROFILE_FILE=` environment variable set to @@ -78,6 +117,7 @@ endif # Generate a coverage report using `llvm-cov show`. "$(LLVM_BIN_DIR)"/llvm-cov show \ $(DEBUG_FLAG) \ + $(LLVM_COV_IGNORE_FILES) \ --Xdemangler="$(RUST_DEMANGLER)" \ --show-line-counts-or-regions \ --instr-profile="$(TMPDIR)"/$@.profdata \ @@ -106,8 +146,17 @@ else # Compare the show coverage output (`--bless` refreshes `typical` files) # Note `llvm-cov show` output for some programs can vary, but can be ignored # by inserting `// ignore-llvm-cov-show-diffs` at the top of the source file. - - $(DIFF) expected_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \ + # + # FIXME(richkadel): It looks like most past variations seem to have been mitigated. None of the + # Rust test source samples have the `// ignore-llvm-cov-show-diffs` anymore. The main variation + # I had seen (and is still present in the new `coverage/lib/used_crate.rs`) is the `llvm-cov show` + # reporting of multiple instantiations of a generic function with different type substitutions. + # For some reason, `llvm-cov show` can report these in a non-deterministic order, breaking the + # `diff` comparision. I was able to work around the problem with `diff --ignore-matching-lines=RE` + # to ignore each line prefixing each generic instantiation coverage code region. + + $(DIFF) --ignore-matching-lines='::<.*>.*:$$' \ + expected_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \ ( grep -q '^\/\/ ignore-llvm-cov-show-diffs' $(SOURCEDIR)/$@.rs && \ >&2 echo 'diff failed, but suppressed with `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs' \ ) || \ @@ -135,11 +184,16 @@ endif # Generate a coverage report in JSON, using `llvm-cov export`, and fail if # there are differences from the expected output. "$(LLVM_BIN_DIR)"/llvm-cov export \ + $(LLVM_COV_IGNORE_FILES) \ --summary-only \ --instr-profile="$(TMPDIR)"/$@.profdata \ $(call BIN,"$(TMPDIR)"/$@) \ | "$(PYTHON)" $(BASEDIR)/prettify_json.py \ > "$(TMPDIR)"/actual_export_coverage.$@.json + # FIXME(richkadel): With the addition of `--ignore-matching-lines=RE` to ignore the + # non-deterministically-ordered coverage results for multiple instantiations of generics with + # differing type substitutions, I probably don't need the `.json` files anymore (and may not + # need `prettify_json.py` either). ifdef RUSTC_BLESS_TEST cp "$(TMPDIR)"/actual_export_coverage.$@.json expected_export_coverage.$@.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loops_branches.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.abort.json similarity index 67% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loops_branches.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.abort.json index 2dca41df9d24e..db7dd0b15e960 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loops_branches.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.abort.json @@ -3,7 +3,7 @@ { "files": [ { - "filename": "../coverage/loops_branches.rs", + "filename": "../coverage/abort.rs", "summary": { "functions": { "count": 2, @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 11, - "covered": 11, - "percent": 100 + "count": 19, + "covered": 17, + "percent": 89.47368421052632 }, "regions": { - "count": 9, - "covered": 8, + "count": 17, + "covered": 16, "notcovered": 1, - "percent": 88.88888888888889 + "percent": 94.11764705882352 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 11, - "covered": 11, - "percent": 100 + "count": 19, + "covered": 17, + "percent": 89.47368421052632 }, "regions": { - "count": 9, - "covered": 8, + "count": 17, + "covered": 16, "notcovered": 1, - "percent": 88.88888888888889 + "percent": 94.11764705882352 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.tight_inf_loop.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json similarity index 64% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.tight_inf_loop.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json index 872560384eb90..024b5f11179ac 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.tight_inf_loop.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json @@ -3,53 +3,53 @@ { "files": [ { - "filename": "../coverage/tight_inf_loop.rs", + "filename": "../coverage/assert.rs", "summary": { "functions": { - "count": 1, - "covered": 1, + "count": 2, + "covered": 2, "percent": 100 }, "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { "count": 2, "covered": 2, "percent": 100 }, + "lines": { + "count": 15, + "covered": 12, + "percent": 80 + }, "regions": { - "count": 2, - "covered": 2, - "notcovered": 0, - "percent": 100 + "count": 14, + "covered": 12, + "notcovered": 2, + "percent": 85.71428571428571 } } } ], "totals": { "functions": { - "count": 1, - "covered": 1, + "count": 2, + "covered": 2, "percent": 100 }, "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { "count": 2, "covered": 2, "percent": 100 }, + "lines": { + "count": 15, + "covered": 12, + "percent": 80 + }, "regions": { - "count": 2, - "covered": 2, - "notcovered": 0, - "percent": 100 + "count": 14, + "covered": 12, + "notcovered": 2, + "percent": 85.71428571428571 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json new file mode 100644 index 0000000000000..794a2e382535a --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/async.rs", + "summary": { + "functions": { + "count": 17, + "covered": 16, + "percent": 94.11764705882352 + }, + "instantiations": { + "count": 17, + "covered": 16, + "percent": 94.11764705882352 + }, + "lines": { + "count": 105, + "covered": 77, + "percent": 73.33333333333333 + }, + "regions": { + "count": 78, + "covered": 36, + "notcovered": 42, + "percent": 46.15384615384615 + } + } + } + ], + "totals": { + "functions": { + "count": 17, + "covered": 16, + "percent": 94.11764705882352 + }, + "instantiations": { + "count": 17, + "covered": 16, + "percent": 94.11764705882352 + }, + "lines": { + "count": 105, + "covered": 77, + "percent": 73.33333333333333 + }, + "regions": { + "count": 78, + "covered": 36, + "notcovered": 42, + "percent": 46.15384615384615 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.closure.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.closure.json new file mode 100644 index 0000000000000..39e1dea66f963 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.closure.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/closure.rs", + "summary": { + "functions": { + "count": 6, + "covered": 4, + "percent": 66.66666666666666 + }, + "instantiations": { + "count": 6, + "covered": 4, + "percent": 66.66666666666666 + }, + "lines": { + "count": 161, + "covered": 131, + "percent": 81.36645962732919 + }, + "regions": { + "count": 42, + "covered": 22, + "notcovered": 20, + "percent": 52.38095238095239 + } + } + } + ], + "totals": { + "functions": { + "count": 6, + "covered": 4, + "percent": 66.66666666666666 + }, + "instantiations": { + "count": 6, + "covered": 4, + "percent": 66.66666666666666 + }, + "lines": { + "count": 161, + "covered": 131, + "percent": 81.36645962732919 + }, + "regions": { + "count": 42, + "covered": 22, + "notcovered": 20, + "percent": 52.38095238095239 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.conditions.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.conditions.json similarity index 66% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.conditions.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.conditions.json index ed937a1b13f38..69356604856b6 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.conditions.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.conditions.json @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 49, - "covered": 23, - "percent": 46.93877551020408 + "count": 64, + "covered": 33, + "percent": 51.5625 }, "regions": { - "count": 69, - "covered": 18, - "notcovered": 51, - "percent": 26.08695652173913 + "count": 64, + "covered": 21, + "notcovered": 43, + "percent": 32.8125 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 49, - "covered": 23, - "percent": 46.93877551020408 + "count": 64, + "covered": 33, + "percent": 51.5625 }, "regions": { - "count": 69, - "covered": 18, - "notcovered": 51, - "percent": 26.08695652173913 + "count": 64, + "covered": 21, + "notcovered": 43, + "percent": 32.8125 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.dead_code.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.dead_code.json new file mode 100644 index 0000000000000..6588ba90274ad --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.dead_code.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/dead_code.rs", + "summary": { + "functions": { + "count": 1, + "covered": 0, + "percent": 0 + }, + "instantiations": { + "count": 1, + "covered": 0, + "percent": 0 + }, + "lines": { + "count": 33, + "covered": 11, + "percent": 33.33333333333333 + }, + "regions": { + "count": 12, + "covered": 3, + "notcovered": 9, + "percent": 25 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 0, + "percent": 0 + }, + "instantiations": { + "count": 1, + "covered": 0, + "percent": 0 + }, + "lines": { + "count": 33, + "covered": 11, + "percent": 33.33333333333333 + }, + "regions": { + "count": 12, + "covered": 3, + "notcovered": 9, + "percent": 25 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.drop_trait.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.drop_trait.json similarity index 83% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.drop_trait.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.drop_trait.json index bd2e2d56d4a55..e303d3802f519 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.drop_trait.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.drop_trait.json @@ -16,13 +16,13 @@ "percent": 100 }, "lines": { - "count": 10, - "covered": 10, + "count": 12, + "covered": 12, "percent": 100 }, "regions": { - "count": 5, - "covered": 5, + "count": 4, + "covered": 4, "notcovered": 0, "percent": 100 } @@ -41,13 +41,13 @@ "percent": 100 }, "lines": { - "count": 10, - "covered": 10, + "count": 12, + "covered": 12, "percent": 100 }, "regions": { - "count": 5, - "covered": 5, + "count": 4, + "covered": 4, "notcovered": 0, "percent": 100 } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.generics.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.generics.json similarity index 83% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.generics.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.generics.json index a50f4657e20aa..bfae69d7ac4dc 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.generics.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.generics.json @@ -16,13 +16,13 @@ "percent": 100 }, "lines": { - "count": 16, - "covered": 16, + "count": 18, + "covered": 18, "percent": 100 }, "regions": { - "count": 6, - "covered": 6, + "count": 5, + "covered": 5, "notcovered": 0, "percent": 100 } @@ -41,13 +41,13 @@ "percent": 100 }, "lines": { - "count": 16, - "covered": 16, + "count": 18, + "covered": 18, "percent": 100 }, "regions": { - "count": 6, - "covered": 6, + "count": 5, + "covered": 5, "notcovered": 0, "percent": 100 } diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.while.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if.json similarity index 83% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.while.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if.json index 339c65556682a..8f233f8bfc548 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.while.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if.json @@ -3,7 +3,7 @@ { "files": [ { - "filename": "../coverage/while.rs", + "filename": "../coverage/if.rs", "summary": { "functions": { "count": 1, @@ -16,9 +16,9 @@ "percent": 100 }, "lines": { - "count": 4, - "covered": 3, - "percent": 75 + "count": 26, + "covered": 26, + "percent": 100 }, "regions": { "count": 4, @@ -41,9 +41,9 @@ "percent": 100 }, "lines": { - "count": 4, - "covered": 3, - "percent": 75 + "count": 26, + "covered": 26, + "percent": 100 }, "regions": { "count": 4, diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if_else.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if_else.json similarity index 85% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if_else.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if_else.json index 36f81ceae19bf..5c0454e1ecbc2 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if_else.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if_else.json @@ -16,9 +16,9 @@ "percent": 100 }, "lines": { - "count": 28, - "covered": 19, - "percent": 67.85714285714286 + "count": 32, + "covered": 23, + "percent": 71.875 }, "regions": { "count": 7, @@ -41,9 +41,9 @@ "percent": 100 }, "lines": { - "count": 28, - "covered": 19, - "percent": 67.85714285714286 + "count": 32, + "covered": 23, + "percent": 71.875 }, "regions": { "count": 7, diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.inner_items.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.inner_items.json similarity index 77% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.inner_items.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.inner_items.json index c178e7f93476f..07ef9a9ab3348 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.inner_items.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.inner_items.json @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 26, - "covered": 26, + "count": 29, + "covered": 29, "percent": 100 }, "regions": { - "count": 15, - "covered": 13, + "count": 11, + "covered": 9, "notcovered": 2, - "percent": 86.66666666666667 + "percent": 81.81818181818183 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 26, - "covered": 26, + "count": 29, + "covered": 29, "percent": 100 }, "regions": { - "count": 15, - "covered": 13, + "count": 11, + "covered": 9, "notcovered": 2, - "percent": 86.66666666666667 + "percent": 81.81818181818183 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.lazy_boolean.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.lazy_boolean.json similarity index 72% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.lazy_boolean.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.lazy_boolean.json index 5a953b90b423f..c3a96b08e6a2a 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.lazy_boolean.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.lazy_boolean.json @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 40, - "covered": 30, + "count": 44, + "covered": 33, "percent": 75 }, "regions": { - "count": 37, - "covered": 26, - "notcovered": 11, - "percent": 70.27027027027027 + "count": 28, + "covered": 21, + "notcovered": 7, + "percent": 75 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 40, - "covered": 30, + "count": 44, + "covered": 33, "percent": 75 }, "regions": { - "count": 37, - "covered": 26, - "notcovered": 11, - "percent": 70.27027027027027 + "count": 28, + "covered": 21, + "notcovered": 7, + "percent": 75 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loop_break_value.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loop_break_value.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loop_break_value.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loop_break_value.json diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.loops_branches.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loops_branches.json similarity index 85% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.loops_branches.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loops_branches.json index 2dca41df9d24e..6d566f2b818c8 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.loops_branches.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loops_branches.json @@ -21,10 +21,10 @@ "percent": 100 }, "regions": { - "count": 9, - "covered": 8, + "count": 8, + "covered": 7, "notcovered": 1, - "percent": 88.88888888888889 + "percent": 87.5 } } } @@ -46,10 +46,10 @@ "percent": 100 }, "regions": { - "count": 9, - "covered": 8, + "count": 8, + "covered": 7, "notcovered": 1, - "percent": 88.88888888888889 + "percent": 87.5 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.loop_break_value.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.nested_loops.json similarity index 66% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.loop_break_value.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.nested_loops.json index 6cb1465c81873..bf3b5cb031b92 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.loop_break_value.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.nested_loops.json @@ -3,7 +3,7 @@ { "files": [ { - "filename": "../coverage/loop_break_value.rs", + "filename": "../coverage/nested_loops.rs", "summary": { "functions": { "count": 1, @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 11, - "covered": 11, - "percent": 100 + "count": 22, + "covered": 17, + "percent": 77.27272727272727 }, "regions": { - "count": 1, - "covered": 1, - "notcovered": 0, - "percent": 100 + "count": 14, + "covered": 11, + "notcovered": 3, + "percent": 78.57142857142857 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 11, - "covered": 11, - "percent": 100 + "count": 22, + "covered": 17, + "percent": 77.27272727272727 }, "regions": { - "count": 1, - "covered": 1, - "notcovered": 0, - "percent": 100 + "count": 14, + "covered": 11, + "notcovered": 3, + "percent": 78.57142857142857 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.drop_trait.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json similarity index 62% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.drop_trait.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json index bd2e2d56d4a55..030d7b033f009 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.drop_trait.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json @@ -3,7 +3,7 @@ { "files": [ { - "filename": "../coverage/drop_trait.rs", + "filename": "../coverage/overflow.rs", "summary": { "functions": { "count": 2, @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 10, - "covered": 10, - "percent": 100 + "count": 23, + "covered": 19, + "percent": 82.6086956521739 }, "regions": { - "count": 5, - "covered": 5, - "notcovered": 0, - "percent": 100 + "count": 13, + "covered": 11, + "notcovered": 2, + "percent": 84.61538461538461 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 10, - "covered": 10, - "percent": 100 + "count": 23, + "covered": 19, + "percent": 82.6086956521739 }, "regions": { - "count": 5, - "covered": 5, - "notcovered": 0, - "percent": 100 + "count": 13, + "covered": 11, + "notcovered": 2, + "percent": 84.61538461538461 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.try_error_result.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json similarity index 66% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.try_error_result.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json index 78b935b15689a..b1d44fdfeac54 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.try_error_result.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json @@ -3,7 +3,7 @@ { "files": [ { - "filename": "../coverage/try_error_result.rs", + "filename": "../coverage/panic_unwind.rs", "summary": { "functions": { "count": 2, @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 20, - "covered": 18, - "percent": 90 + "count": 19, + "covered": 16, + "percent": 84.21052631578947 }, "regions": { - "count": 19, - "covered": 14, - "notcovered": 5, - "percent": 73.68421052631578 + "count": 13, + "covered": 11, + "notcovered": 2, + "percent": 84.61538461538461 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 20, - "covered": 18, - "percent": 90 + "count": 19, + "covered": 16, + "percent": 84.21052631578947 }, "regions": { - "count": 19, - "covered": 14, - "notcovered": 5, - "percent": 73.68421052631578 + "count": 13, + "covered": 11, + "notcovered": 2, + "percent": 84.61538461538461 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.partial_eq.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.partial_eq.json similarity index 54% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.partial_eq.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.partial_eq.json index a7b98247b6631..6a0d83a6d0e44 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.partial_eq.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.partial_eq.json @@ -7,24 +7,24 @@ "summary": { "functions": { "count": 5, - "covered": 5, - "percent": 100 + "covered": 4, + "percent": 80 }, "instantiations": { "count": 5, - "covered": 5, - "percent": 100 + "covered": 4, + "percent": 80 }, "lines": { - "count": 15, - "covered": 15, - "percent": 100 + "count": 18, + "covered": 16, + "percent": 88.88888888888889 }, "regions": { - "count": 6, - "covered": 6, - "notcovered": 0, - "percent": 100 + "count": 24, + "covered": 5, + "notcovered": 19, + "percent": 20.833333333333336 } } } @@ -32,24 +32,24 @@ "totals": { "functions": { "count": 5, - "covered": 5, - "percent": 100 + "covered": 4, + "percent": 80 }, "instantiations": { "count": 5, - "covered": 5, - "percent": 100 + "covered": 4, + "percent": 80 }, "lines": { - "count": 15, - "covered": 15, - "percent": 100 + "count": 18, + "covered": 16, + "percent": 88.88888888888889 }, "regions": { - "count": 6, - "covered": 6, - "notcovered": 0, - "percent": 100 + "count": 24, + "covered": 5, + "notcovered": 19, + "percent": 20.833333333333336 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_loop.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_loop.json similarity index 77% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_loop.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_loop.json index ada6bb062dd1e..4c849692a034c 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_loop.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_loop.json @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 19, - "covered": 19, + "count": 25, + "covered": 25, "percent": 100 }, "regions": { - "count": 9, - "covered": 8, + "count": 7, + "covered": 6, "notcovered": 1, - "percent": 88.88888888888889 + "percent": 85.71428571428571 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 19, - "covered": 19, + "count": 25, + "covered": 25, "percent": 100 }, "regions": { - "count": 9, - "covered": 8, + "count": 7, + "covered": 6, "notcovered": 1, - "percent": 88.88888888888889 + "percent": 85.71428571428571 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_match.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_match.json similarity index 77% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_match.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_match.json index 63d1ae74c5f5d..41bc4d57d59f4 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_match.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_match.json @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 24, - "covered": 24, + "count": 27, + "covered": 27, "percent": 100 }, "regions": { - "count": 15, - "covered": 14, + "count": 11, + "covered": 10, "notcovered": 1, - "percent": 93.33333333333333 + "percent": 90.9090909090909 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 24, - "covered": 24, + "count": 27, + "covered": 27, "percent": 100 }, "regions": { - "count": 15, - "covered": 14, + "count": 11, + "covered": 10, "notcovered": 1, - "percent": 93.33333333333333 + "percent": 90.9090909090909 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.tight_inf_loop.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.tight_inf_loop.json similarity index 91% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.tight_inf_loop.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.tight_inf_loop.json index 872560384eb90..7f6c90b92d296 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.tight_inf_loop.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.tight_inf_loop.json @@ -16,8 +16,8 @@ "percent": 100 }, "lines": { - "count": 2, - "covered": 2, + "count": 4, + "covered": 4, "percent": 100 }, "regions": { @@ -41,8 +41,8 @@ "percent": 100 }, "lines": { - "count": 2, - "covered": 2, + "count": 4, + "covered": 4, "percent": 100 }, "regions": { diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.try_error_result.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.try_error_result.json similarity index 80% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.try_error_result.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.try_error_result.json index 78b935b15689a..df4de9dc54bdc 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.try_error_result.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.try_error_result.json @@ -21,10 +21,10 @@ "percent": 90 }, "regions": { - "count": 19, - "covered": 14, - "notcovered": 5, - "percent": 73.68421052631578 + "count": 16, + "covered": 12, + "notcovered": 4, + "percent": 75 } } } @@ -46,10 +46,10 @@ "percent": 90 }, "regions": { - "count": 19, - "covered": 14, - "notcovered": 5, - "percent": 73.68421052631578 + "count": 16, + "covered": 12, + "notcovered": 4, + "percent": 75 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json new file mode 100644 index 0000000000000..35ddd58fc437a --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/lib/used_crate.rs", + "summary": { + "functions": { + "count": 6, + "covered": 5, + "percent": 83.33333333333334 + }, + "instantiations": { + "count": 10, + "covered": 8, + "percent": 80 + }, + "lines": { + "count": 46, + "covered": 26, + "percent": 56.52173913043478 + }, + "regions": { + "count": 19, + "covered": 8, + "notcovered": 11, + "percent": 42.10526315789473 + } + } + } + ], + "totals": { + "functions": { + "count": 6, + "covered": 5, + "percent": 83.33333333333334 + }, + "instantiations": { + "count": 10, + "covered": 8, + "percent": 80 + }, + "lines": { + "count": 46, + "covered": 26, + "percent": 56.52173913043478 + }, + "regions": { + "count": 19, + "covered": 8, + "notcovered": 11, + "percent": 42.10526315789473 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while.json similarity index 87% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while.json index 339c65556682a..339c533ada6dc 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while.json @@ -16,9 +16,9 @@ "percent": 100 }, "lines": { - "count": 4, - "covered": 3, - "percent": 75 + "count": 5, + "covered": 4, + "percent": 80 }, "regions": { "count": 4, @@ -41,9 +41,9 @@ "percent": 100 }, "lines": { - "count": 4, - "covered": 3, - "percent": 75 + "count": 5, + "covered": 4, + "percent": 80 }, "regions": { "count": 4, diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while_early_ret.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while_early_ret.json similarity index 85% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while_early_ret.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while_early_ret.json index ad43f5d992630..b7fe2a0fb47df 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while_early_ret.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while_early_ret.json @@ -16,9 +16,9 @@ "percent": 100 }, "lines": { - "count": 17, - "covered": 15, - "percent": 88.23529411764706 + "count": 19, + "covered": 17, + "percent": 89.47368421052632 }, "regions": { "count": 9, @@ -41,9 +41,9 @@ "percent": 100 }, "lines": { - "count": 17, - "covered": 15, - "percent": 88.23529411764706 + "count": 19, + "covered": 17, + "percent": 89.47368421052632 }, "regions": { "count": 9, diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.generics.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.yield.json similarity index 55% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.generics.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.yield.json index a50f4657e20aa..6fc41212bc091 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.generics.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.yield.json @@ -3,7 +3,7 @@ { "files": [ { - "filename": "../coverage/generics.rs", + "filename": "../coverage/yield.rs", "summary": { "functions": { "count": 3, @@ -11,20 +11,20 @@ "percent": 100 }, "instantiations": { - "count": 5, - "covered": 5, + "count": 3, + "covered": 3, "percent": 100 }, "lines": { - "count": 16, - "covered": 16, - "percent": 100 + "count": 26, + "covered": 19, + "percent": 73.07692307692307 }, "regions": { - "count": 6, - "covered": 6, - "notcovered": 0, - "percent": 100 + "count": 23, + "covered": 17, + "notcovered": 6, + "percent": 73.91304347826086 } } } @@ -36,20 +36,20 @@ "percent": 100 }, "instantiations": { - "count": 5, - "covered": 5, + "count": 3, + "covered": 3, "percent": 100 }, "lines": { - "count": 16, - "covered": 16, - "percent": 100 + "count": 26, + "covered": 19, + "percent": 73.07692307692307 }, "regions": { - "count": 6, - "covered": 6, - "notcovered": 0, - "percent": 100 + "count": 23, + "covered": 17, + "notcovered": 6, + "percent": 73.91304347826086 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.abort.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.abort.txt new file mode 100644 index 0000000000000..3b5d5eb422702 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.abort.txt @@ -0,0 +1,70 @@ + 1| |#![feature(unwind_attributes)] + 2| |#![allow(unused_assignments)] + 3| | + 4| |#[unwind(aborts)] + 5| 12|fn might_abort(should_abort: bool) { + 6| 12| if should_abort { + 7| 0| println!("aborting..."); + 8| 0| panic!("panics and aborts"); + 9| 12| } else { + 10| 12| println!("Don't Panic"); + 11| 12| } + 12| 12|} + 13| | + 14| 1|fn main() -> Result<(), u8> { + 15| 1| let mut countdown = 10; + 16| 11| while countdown > 0 { + 17| 10| if countdown < 5 { + 18| 4| might_abort(false); + 19| 6| } + 20| | // See discussion (below the `Notes` section) on coverage results for the closing brace. + 21| 10| if countdown < 5 { might_abort(false); } // Counts for different regions on one line. + ^4 ^6 + 22| | // For the following example, the closing brace is the last character on the line. + 23| | // This shows the character after the closing brace is highlighted, even if that next + 24| | // character is a newline. + 25| 10| if countdown < 5 { might_abort(false); } + ^4 ^6 + 26| 10| countdown -= 1; + 27| | } + 28| 1| Ok(()) + 29| 1|} + 30| | + 31| |// Notes: + 32| |// 1. Compare this program and its coverage results to those of the similar tests + 33| |// `panic_unwind.rs` and `try_error_result.rs`. + 34| |// 2. This test confirms the coverage generated when a program includes `TerminatorKind::Abort`. + 35| |// 3. The test does not invoke the abort. By executing to a successful completion, the coverage + 36| |// results show where the program did and did not execute. + 37| |// 4. If the program actually aborted, the coverage counters would not be saved (which "works as + 38| |// intended"). Coverage results would show no executed coverage regions. + 39| |// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status + 40| |// (on Linux at least). + 41| | + 42| |/* + 43| | + 44| |Expect the following coverage results: + 45| | + 46| |```text + 47| | 16| 11| while countdown > 0 { + 48| | 17| 10| if countdown < 5 { + 49| | 18| 4| might_abort(false); + 50| | 19| 6| } + 51| |``` + 52| | + 53| |This is actually correct. + 54| | + 55| |The condition `countdown < 5` executed 10 times (10 loop iterations). + 56| | + 57| |It evaluated to `true` 4 times, and executed the `might_abort()` call. + 58| | + 59| |It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit + 60| |`else`, the coverage implementation injects a counter, at the character immediately after the `if`s + 61| |closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the + 62| |non-true condition. + 63| | + 64| |As another example of why this is important, say the condition was `countdown < 50`, which is always + 65| |`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called. + 66| |The closing brace would have a count of `0`, highlighting the missed coverage. + 67| |*/ + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt new file mode 100644 index 0000000000000..355b53f7f3b69 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt @@ -0,0 +1,34 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-101 + 3| | + 4| 4|fn might_fail_assert(one_plus_one: u32) { + 5| 4| println!("does 1 + 1 = {}?", one_plus_one); + 6| 4| assert_eq!(1 + 1, one_plus_one, "the argument was wrong"); + ^1 + 7| 3|} + 8| | + 9| 1|fn main() -> Result<(),u8> { + 10| 1| let mut countdown = 10; + 11| 10| while countdown > 0 { + 12| 10| if countdown == 1 { + 13| 0| might_fail_assert(3); + 14| 10| } else if countdown < 5 { + 15| 3| might_fail_assert(2); + 16| 6| } + 17| 9| countdown -= 1; + 18| | } + 19| 0| Ok(()) + 20| 0|} + 21| | + 22| |// Notes: + 23| |// 1. Compare this program and its coverage results to those of the very similar test + 24| |// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`. + 25| |// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or + 26| |// related `assert_*!()` macro. + 27| |// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce + 28| |// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to + 29| |// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). + 30| |// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test + 31| |// (and in many other coverage tests). The `Assert` terminator is typically generated by the + 32| |// Rust compiler to check for runtime failures, such as numeric overflows. + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt new file mode 100644 index 0000000000000..824bddaa40155 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt @@ -0,0 +1,135 @@ + 1| |#![allow(unused_assignments, dead_code)] + 2| | + 3| |// require-rust-edition-2018 + 4| | + 5| 1|async fn c(x: u8) -> u8 { + 6| 1| if x == 8 { + 7| 1| 1 + 8| | } else { + 9| 0| 0 + 10| | } + 11| 1|} + 12| | + 13| 0|async fn d() -> u8 { 1 } + 14| | + 15| 0|async fn e() -> u8 { 1 } // unused function; executor does not block on `g()` + 16| | + 17| 1|async fn f() -> u8 { 1 } + 18| | + 19| 0|async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` + 20| | + 21| 1|pub async fn g(x: u8) { + 22| 0| match x { + 23| 0| y if e().await == y => (), + 24| 0| y if f().await == y => (), + 25| 0| _ => (), + 26| | } + 27| 0|} + 28| | + 29| 1|async fn h(x: usize) { // The function signature is counted when called, but the body is not + 30| 0| // executed (not awaited) so the open brace has a `0` count (at least when + 31| 0| // displayed with `llvm-cov show` in color-mode). + 32| 0| match x { + 33| 0| y if foo().await[y] => (), + 34| 0| _ => (), + 35| | } + 36| 0|} + 37| | + 38| 1|async fn i(x: u8) { // line coverage is 1, but there are 2 regions: + 39| 1| // (a) the function signature, counted when the function is called; and + 40| 1| // (b) the open brace for the function body, counted once when the body is + 41| 1| // executed asynchronously. + 42| 1| match x { + 43| 1| y if c(x).await == y + 1 => { d().await; } + ^0 ^0 + 44| 1| y if f().await == y + 1 => (), + ^0 ^0 + 45| 1| _ => (), + 46| | } + 47| 1|} + 48| | + 49| 1|fn j(x: u8) { + 50| 1| // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`. + 51| 1| fn c(x: u8) -> u8 { + 52| 1| if x == 8 { + 53| 1| 1 // This line appears covered, but the 1-character expression span covering the `1` + ^0 + 54| 1| // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because + 55| 1| // `fn j()` executes the open brace for the funciton body, followed by the function's + 56| 1| // first executable statement, `match x`. Inner function declarations are not + 57| 1| // "visible" to the MIR for `j()`, so the code region counts all lines between the + 58| 1| // open brace and the first statement as executed, which is, in a sense, true. + 59| 1| // `llvm-cov show` overcomes this kind of situation by showing the actual counts + 60| 1| // of the enclosed coverages, (that is, the `1` expression was not executed, and + 61| 1| // accurately displays a `0`). + 62| 1| } else { + 63| 1| 0 + 64| 1| } + 65| 1| } + 66| 1| fn d() -> u8 { 1 } + 67| 1| fn f() -> u8 { 1 } + 68| 1| match x { + 69| 1| y if c(x) == y + 1 => { d(); } + ^0 ^0 + 70| 1| y if f() == y + 1 => (), + ^0 ^0 + 71| 1| _ => (), + 72| | } + 73| 1|} + 74| | + 75| 0|fn k(x: u8) { // unused function + 76| 0| match x { + 77| 0| 1 => (), + 78| 0| 2 => (), + 79| 0| _ => (), + 80| | } + 81| 0|} + 82| | + 83| 1|fn l(x: u8) { + 84| 1| match x { + 85| 0| 1 => (), + 86| 0| 2 => (), + 87| 1| _ => (), + 88| | } + 89| 1|} + 90| | + 91| 1|async fn m(x: u8) -> u8 { x - 1 } + ^0 + 92| | + 93| 1|fn main() { + 94| 1| let _ = g(10); + 95| 1| let _ = h(9); + 96| 1| let mut future = Box::pin(i(8)); + 97| 1| j(7); + 98| 1| l(6); + 99| 1| let _ = m(5); + 100| 1| executor::block_on(future.as_mut()); + 101| 1|} + 102| | + 103| |mod executor { + 104| | use core::{ + 105| | future::Future, + 106| | pin::Pin, + 107| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + 108| | }; + 109| | + 110| 1| pub fn block_on(mut future: F) -> F::Output { + 111| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + 112| 1| + 113| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + 114| 1| |_| unimplemented!("clone"), + 115| 1| |_| unimplemented!("wake"), + 116| 1| |_| unimplemented!("wake_by_ref"), + 117| 1| |_| (), + 118| 1| ); + 119| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + 120| 1| let mut context = Context::from_waker(&waker); + 121| | + 122| | loop { + 123| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + 124| 1| break val; + 125| 0| } + 126| | } + 127| 1| } + 128| |} + diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.closure.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt similarity index 51% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.closure.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt index aef26a62e25fb..7261cf0a3b0da 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.closure.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt @@ -16,7 +16,7 @@ 16| 1| unwrap_or_else 17| 1| ( 18| 1| || - 19| | { + 19| 0| { 20| 0| let mut countdown = 0; 21| 0| if is_false { 22| 0| countdown = 10; @@ -31,7 +31,7 @@ 31| 1| a 32| 1| = 33| 1| || - 34| | { + 34| 0| { 35| 0| let mut countdown = 0; 36| 0| if is_false { 37| 0| countdown = 10; @@ -58,7 +58,7 @@ 58| 1| unwrap_or_else 59| 1| ( 60| 1| || - 61| | { + 61| 1| { 62| 1| let mut countdown = 0; 63| 1| if is_false { 64| 0| countdown = 10; @@ -73,7 +73,7 @@ 73| 1| a 74| 1| = 75| 1| || - 76| | { + 76| 1| { 77| 1| let mut countdown = 0; 78| 1| if is_false { 79| 0| countdown = 10; @@ -90,5 +90,71 @@ 90| 1| a 91| 1| ) 92| 1| ); - 93| 1|} + 93| 1| + 94| 1| let + 95| 1| quote_closure + 96| 1| = + 97| 1| |val| + 98| 5| { + 99| 5| let mut countdown = 0; + 100| 5| if is_false { + 101| 0| countdown = 10; + 102| 5| } + 103| 5| format!("'{}'", val) + 104| 5| }; + 105| 1| println!( + 106| 1| "Repeated, quoted string: {:?}" + 107| 1| , + 108| 1| std::iter::repeat("repeat me") + 109| 1| .take(5) + 110| 1| .map + 111| 1| ( + 112| 1| quote_closure + 113| 1| ) + 114| 1| .collect::>() + 115| 1| ); + 116| 1| + 117| 1| let + 118| 1| _unused_closure + 119| 1| = + 120| 1| | + 121| | mut countdown + 122| | | + 123| 0| { + 124| 0| if is_false { + 125| 0| countdown = 10; + 126| 0| } + 127| 0| "closure should be unused".to_owned() + 128| 1| }; + 129| 1| + 130| 1| let mut countdown = 10; + 131| 1| let _short_unused_closure = | _unused_arg: u8 | countdown += 1; + ^0 + 132| 1| + 133| 1| // Macros can sometimes confuse the coverage results. Compare this next assignment, with an + 134| 1| // unused closure that invokes the `println!()` macro, with the closure assignment above, that + 135| 1| // does not use a macro. The closure above correctly shows `0` executions. + 136| 1| let _short_unused_closure = | _unused_arg: u8 | println!("not called"); + 137| 1| // The closure assignment above is executed, with a line count of `1`, but the `println!()` + 138| 1| // could not have been called, and yet, there is no indication that it wasn't... + 139| 1| + 140| 1| // ...but adding block braces gives the expected result, showing the block was not executed. + 141| 1| let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; + ^0 + 142| 1| + 143| 1| let _shortish_unused_closure = | _unused_arg: u8 | { + 144| 0| println!("not called") + 145| 1| }; + 146| 1| + 147| 1| let _as_short_unused_closure = | + 148| | _unused_arg: u8 + 149| 1| | { println!("not called") }; + ^0 + 150| 1| + 151| 1| let _almost_as_short_unused_closure = | + 152| | _unused_arg: u8 + 153| 1| | { println!("not called") } + ^0 + 154| 1| ; + 155| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt new file mode 100644 index 0000000000000..656a26597759d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt @@ -0,0 +1,90 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| 1|fn main() { + 4| 1| let mut countdown = 0; + 5| 1| if true { + 6| 1| countdown = 10; + 7| 1| } + 8| | + 9| | const B: u32 = 100; + 10| 1| let x = if countdown > 7 { + 11| 1| countdown -= 4; + 12| 1| B + 13| 0| } else if countdown > 2 { + 14| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 15| 0| countdown = 0; + 16| 0| } + 17| 0| countdown -= 5; + 18| 0| countdown + 19| | } else { + 20| 0| return; + 21| | }; + 22| | + 23| 1| let mut countdown = 0; + 24| 1| if true { + 25| 1| countdown = 10; + 26| 1| } + 27| | + 28| 1| if countdown > 7 { + 29| 1| countdown -= 4; + 30| 1| } else if countdown > 2 { + ^0 + 31| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 32| 0| countdown = 0; + 33| 0| } + 34| 0| countdown -= 5; + 35| | } else { + 36| 0| return; + 37| | } + 38| | + 39| 1| if true { + 40| 1| let mut countdown = 0; + 41| 1| if true { + 42| 1| countdown = 10; + 43| 1| } + 44| | + 45| 1| if countdown > 7 { + 46| 1| countdown -= 4; + 47| 1| } + 48| 0| else if countdown > 2 { + 49| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 50| 0| countdown = 0; + 51| 0| } + 52| 0| countdown -= 5; + 53| | } else { + 54| 0| return; + 55| | } + 56| | } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal + 57| | // `true` was const-evaluated. The compiler knows the `if` block will be executed. + 58| | + 59| 1| let mut countdown = 0; + 60| 1| if true { + 61| 1| countdown = 1; + 62| 1| } + 63| | + 64| 1| let z = if countdown > 7 { + ^0 + 65| 0| countdown -= 4; + 66| 1| } else if countdown > 2 { + 67| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 68| 0| countdown = 0; + 69| 0| } + 70| 0| countdown -= 5; + 71| | } else { + 72| 1| let should_be_reachable = countdown; + 73| 1| println!("reached"); + 74| 1| return; + 75| | }; + 76| | + 77| 0| let w = if countdown > 7 { + 78| 0| countdown -= 4; + 79| 0| } else if countdown > 2 { + 80| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 81| 0| countdown = 0; + 82| 0| } + 83| 0| countdown -= 5; + 84| | } else { + 85| 0| return; + 86| | }; + 87| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.dead_code.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.dead_code.txt new file mode 100644 index 0000000000000..09ff14c6f2722 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.dead_code.txt @@ -0,0 +1,39 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| 0|pub fn unused_pub_fn_not_in_library() { + 4| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 0| // dependent conditions. + 7| 0| let is_true = std::env::args().len() == 1; + 8| 0| + 9| 0| let mut countdown = 0; + 10| 0| if is_true { + 11| 0| countdown = 10; + 12| 0| } + 13| 0|} + 14| | + 15| 0|fn unused_fn() { + 16| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 17| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 18| 0| // dependent conditions. + 19| 0| let is_true = std::env::args().len() == 1; + 20| 0| + 21| 0| let mut countdown = 0; + 22| 0| if is_true { + 23| 0| countdown = 10; + 24| 0| } + 25| 0|} + 26| | + 27| 1|fn main() { + 28| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 29| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 30| 1| // dependent conditions. + 31| 1| let is_true = std::env::args().len() == 1; + 32| 1| + 33| 1| let mut countdown = 0; + 34| 1| if is_true { + 35| 1| countdown = 10; + 36| 1| } + ^0 + 37| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt similarity index 94% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.drop_trait.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt index 72aa020ca1691..fab5be41901c9 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.drop_trait.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt @@ -11,11 +11,11 @@ 11| 2| } 12| |} 13| | - 14| |fn main() -> Result<(),u8> { + 14| 1|fn main() -> Result<(),u8> { 15| 1| let _firecracker = Firework { strength: 1 }; 16| 1| 17| 1| let _tnt = Firework { strength: 100 }; - 18| | + 18| 1| 19| 1| if true { 20| 1| println!("Exiting with error..."); 21| 1| return Err(1); diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt similarity index 69% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.generics.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt index 86199d7476302..7b38ffb87cba8 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.generics.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt @@ -41,27 +41,31 @@ ------------------ 20| |} 21| | - 22| |fn main() -> Result<(),u8> { + 22| 1|fn main() -> Result<(),u8> { 23| 1| let mut firecracker = Firework { strength: 1 }; 24| 1| firecracker.set_strength(2); 25| 1| 26| 1| let mut tnt = Firework { strength: 100.1 }; 27| 1| tnt.set_strength(200.1); 28| 1| tnt.set_strength(300.3); - 29| | + 29| 1| 30| 1| if true { 31| 1| println!("Exiting with error..."); 32| 1| return Err(1); - 33| | } - 34| | - 35| | let _ = Firework { strength: 1000 }; - 36| | - 37| | Ok(()) - 38| 1|} - 39| | - 40| |// Expected program output: - 41| |// Exiting with error... - 42| |// BOOM times 100!!! - 43| |// BOOM times 1!!! - 44| |// Error: 1 + 33| | } // The remaining lines below have no coverage because `if true` (with the constant literal + 34| | // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`. + 35| | // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown + 36| | // in other tests, the lines below would have coverage (which would show they had `0` + 37| | // executions, assuming the condition still evaluated to `true`). + 38| | + 39| | let _ = Firework { strength: 1000 }; + 40| | + 41| | Ok(()) + 42| 1|} + 43| | + 44| |// Expected program output: + 45| |// Exiting with error... + 46| |// BOOM times 100!!! + 47| |// BOOM times 1!!! + 48| |// Error: 1 diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if.txt similarity index 71% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if.txt index 85e6440ab3729..0c9eff227ed0c 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if.txt @@ -1,10 +1,10 @@ 1| |#![allow(unused_assignments, unused_variables)] 2| | - 3| |fn main() { - 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| | // dependent conditions. - 7| | let + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let 8| 1| is_true 9| 1| = 10| 1| std::env::args().len() @@ -16,8 +16,8 @@ 16| 1| countdown 17| 1| = 18| 1| 0 - 19| | ; - 20| | if + 19| 1| ; + 20| 1| if 21| 1| is_true 22| 1| { 23| 1| countdown diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if_else.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if_else.txt similarity index 79% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if_else.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if_else.txt index 5f899723e2554..4285d31868689 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if_else.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if_else.txt @@ -1,9 +1,9 @@ - 1| |#![allow(unused_assignments)] + 1| |#![allow(unused_assignments, unused_variables)] 2| | - 3| |fn main() { - 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| | // dependent conditions. + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. 7| 1| let is_true = std::env::args().len() == 1; 8| 1| 9| 1| let mut countdown = 0; diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt similarity index 90% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.inner_items.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt index 4a51f842a4bb2..f5b5184044f65 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.inner_items.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt @@ -1,6 +1,6 @@ - 1| |#![allow(unused_assignments, unused_variables)] + 1| |#![allow(unused_assignments, unused_variables, dead_code)] 2| | - 3| |fn main() { + 3| 1|fn main() { 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from 6| | // dependent conditions. @@ -16,7 +16,7 @@ 15| | const IN_MOD_CONST: u32 = 1000; 16| | } 17| | - 18| | fn in_func(a: u32) { + 18| 3| fn in_func(a: u32) { 19| 3| let b = 1; 20| 3| let c = a + b; 21| 3| println!("c = {}", c) @@ -38,7 +38,7 @@ 37| | } 38| | 39| | impl InTrait for InStruct { - 40| | fn trait_func(&mut self, incr: u32) { + 40| 1| fn trait_func(&mut self, incr: u32) { 41| 1| self.in_struct_field += incr; 42| 1| in_func(self.in_struct_field); 43| 1| } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.lazy_boolean.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.lazy_boolean.txt similarity index 86% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.lazy_boolean.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.lazy_boolean.txt index 1b503033911c5..bd349df2fbce2 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.lazy_boolean.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.lazy_boolean.txt @@ -1,9 +1,9 @@ 1| |#![allow(unused_assignments, unused_variables)] 2| | - 3| |fn main() { - 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| | // dependent conditions. + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. 7| 1| let is_true = std::env::args().len() == 1; 8| 1| 9| 1| let (mut a, mut b, mut c) = (0, 0, 0); @@ -18,8 +18,7 @@ 17| | = 18| 1| a < b 19| | || - 20| 1| b < c - ^0 + 20| 0| b < c 21| | ; 22| | let 23| 1| somebool diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loop_break_value.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loop_break_value.txt similarity index 82% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loop_break_value.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loop_break_value.txt index b0d668c6d76da..022fe4c596207 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loop_break_value.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loop_break_value.txt @@ -1,4 +1,4 @@ - 1| |#![allow(unused_assignments)] + 1| |#![allow(unused_assignments, unused_variables)] 2| | 3| 1|fn main() { 4| 1| let result diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt similarity index 89% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loops_branches.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt index 3a969a6b89869..474f02b700734 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loops_branches.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt @@ -1,4 +1,4 @@ - 1| |#![allow(unused_assignments)] + 1| |#![allow(unused_assignments, unused_variables, while_true)] 2| | 3| |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the 4| |// structure of this `fmt` function. @@ -6,7 +6,7 @@ 6| |struct DebugTest; 7| | 8| |impl std::fmt::Debug for DebugTest { - 9| | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + 9| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 10| 1| if true { 11| 1| if false { 12| | while true { @@ -15,7 +15,7 @@ 15| 1| write!(f, "error")?; ^0 16| | } else { - 17| 1| } + 17| | } 18| 1| Ok(()) 19| 1| } 20| |} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.nested_loops.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.nested_loops.txt similarity index 84% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.nested_loops.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.nested_loops.txt index c9f373bf6a7c0..0dbd6bcf313e0 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.nested_loops.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.nested_loops.txt @@ -1,4 +1,4 @@ - 1| |fn main() { + 1| 1|fn main() { 2| 1| let is_true = std::env::args().len() == 1; 3| 1| let mut countdown = 10; 4| | @@ -8,19 +8,19 @@ 8| 3| for _ in 0..50 { 9| 3| if a < 30 { 10| 0| break; - 11| | } + 11| 3| } 12| 3| a -= 5; 13| 3| b -= 5; 14| 3| if b < 90 { 15| 1| a -= 10; 16| 1| if is_true { 17| 1| break 'outer; - 18| | } else { + 18| 0| } else { 19| 0| a -= 2; 20| 0| } 21| 2| } - 22| 2| } + 22| | } 23| 0| countdown -= 1; - 24| 0| } + 24| | } 25| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt new file mode 100644 index 0000000000000..4dccb3413eae9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt @@ -0,0 +1,64 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-101 + 3| | + 4| 4|fn might_overflow(to_add: u32) -> u32 { + 5| 4| if to_add > 5 { + 6| 1| println!("this will probably overflow"); + 7| 3| } + 8| 4| let add_to = u32::MAX - 5; + 9| 4| println!("does {} + {} overflow?", add_to, to_add); + 10| 4| let result = to_add + add_to; + 11| 4| println!("continuing after overflow check"); + 12| 4| result + 13| 4|} + 14| | + 15| 1|fn main() -> Result<(),u8> { + 16| 1| let mut countdown = 10; + 17| 10| while countdown > 0 { + 18| 10| if countdown == 1 { + 19| 0| let result = might_overflow(10); + 20| 0| println!("Result: {}", result); + 21| 10| } else if countdown < 5 { + 22| 3| let result = might_overflow(1); + 23| 3| println!("Result: {}", result); + 24| 6| } + 25| 9| countdown -= 1; + 26| | } + 27| 0| Ok(()) + 28| 0|} + 29| | + 30| |// Notes: + 31| |// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`, + 32| |// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`. + 33| |// 2. This test confirms the coverage generated when a program passes or fails a + 34| |// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case). + 35| |// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`, + 36| |// compiler-generated assertion failures are assumed to be a symptom of a program bug, not + 37| |// expected behavior. To simplify the coverage graphs and keep instrumented programs as + 38| |// small and fast as possible, `Assert` terminators are assumed to always succeed, and + 39| |// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not + 40| |// get its own coverage counter. + 41| |// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive. + 42| |// In this test, the final count for the statements after the `if` block in `might_overflow()` + 43| |// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending + 44| |// on the MIR graph and the structure of the code, this count could have been 3 (which might + 45| |// have been valid for the overflowed add `+`, but should have been 4 for the lines before + 46| |// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented + 47| |// via StatementKind::Counter at the end of the block, but (as in the case in this test), + 48| |// a CounterKind::Expression is always evaluated. In this case, the expression was based on + 49| |// a `Counter` incremented as part of the evaluation of the `if` expression, which was + 50| |// executed, and counted, 4 times, before reaching the overflow add. + 51| | + 52| |// If the program did not overflow, the coverage for `might_overflow()` would look like this: + 53| |// + 54| |// 4| |fn might_overflow(to_add: u32) -> u32 { + 55| |// 5| 4| if to_add > 5 { + 56| |// 6| 0| println!("this will probably overflow"); + 57| |// 7| 4| } + 58| |// 8| 4| let add_to = u32::MAX - 5; + 59| |// 9| 4| println!("does {} + {} overflow?", add_to, to_add); + 60| |// 10| 4| let result = to_add + add_to; + 61| |// 11| 4| println!("continuing after overflow check"); + 62| |// 12| 4| result + 63| |// 13| 4|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt new file mode 100644 index 0000000000000..9ae78fee4b5e1 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt @@ -0,0 +1,50 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-101 + 3| | + 4| 4|fn might_panic(should_panic: bool) { + 5| 4| if should_panic { + 6| 1| println!("panicking..."); + 7| 1| panic!("panics"); + 8| 3| } else { + 9| 3| println!("Don't Panic"); + 10| 3| } + 11| 3|} + 12| | + 13| 1|fn main() -> Result<(), u8> { + 14| 1| let mut countdown = 10; + 15| 10| while countdown > 0 { + 16| 10| if countdown == 1 { + 17| 0| might_panic(true); + 18| 10| } else if countdown < 5 { + 19| 3| might_panic(false); + 20| 6| } + 21| 9| countdown -= 1; + 22| | } + 23| 0| Ok(()) + 24| 0|} + 25| | + 26| |// Notes: + 27| |// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and + 28| |// `try_error_result.rs`. + 29| |// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the + 30| |// normal program exit cleanup, including writing out the current values of the coverage + 31| |// counters. + 32| |// 3. The coverage results show (interestingly) that the `panic!()` call did execute, but it does + 33| |// not show coverage of the `if countdown == 1` branch in `main()` that calls + 34| |// `might_panic(true)` (causing the call to `panic!()`). + 35| |// 4. The reason `main()`s `if countdown == 1` branch, calling `might_panic(true)`, appears + 36| |// "uncovered" is, InstrumentCoverage (intentionally) treats `TerminatorKind::Call` terminators + 37| |// as non-branching, because when a program executes normally, they always are. Errors handled + 38| |// via the try `?` operator produce error handling branches that *are* treated as branches in + 39| |// coverage results. By treating calls without try `?` operators as non-branching (assumed to + 40| |// return normally and continue) the coverage graph can be simplified, producing smaller, + 41| |// faster binaries, and cleaner coverage results. + 42| |// 5. The reason the coverage results actually show `panic!()` was called is most likely because + 43| |// `panic!()` is a macro, not a simple function call, and there are other `Statement`s and/or + 44| |// `Terminator`s that execute with a coverage counter before the panic and unwind occur. + 45| |// 6. Since the common practice is not to use `panic!()` for error handling, the coverage + 46| |// implementation avoids incurring an additional cost (in program size and execution time) to + 47| |// improve coverage results for an event that is generally not "supposed" to happen. + 48| |// 7. FIXME(#78544): This issue describes a feature request for a proposed option to enable + 49| |// more accurate coverage results for tests that intentionally panic. + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt new file mode 100644 index 0000000000000..0fe124f12d906 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt @@ -0,0 +1,63 @@ + 1| |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the + 2| |// structure of this test. + 3| | + 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] + ^0 ^0 ^0 ^0 ^1 ^0 ^0^0 + 5| |pub struct Version { + 6| | major: usize, + 7| 1| minor: usize, // Count: 1 - `PartialOrd` compared `minor` values in 3.2.1 vs. 3.3.0 + 8| 0| patch: usize, // Count: 0 - `PartialOrd` was determined by `minor` (2 < 3) + 9| |} + 10| | + 11| |impl Version { + 12| 2| pub fn new(major: usize, minor: usize, patch: usize) -> Self { + 13| 2| Self { + 14| 2| major, + 15| 2| minor, + 16| 2| patch, + 17| 2| } + 18| 2| } + 19| |} + 20| | + 21| 1|fn main() { + 22| 1| let version_3_2_1 = Version::new(3, 2, 1); + 23| 1| let version_3_3_0 = Version::new(3, 3, 0); + 24| 1| + 25| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); + 26| 1|} + 27| | + 28| |/* + 29| | + 30| |This test verifies a bug was fixed that otherwise generated this error: + 31| | + 32| |thread 'rustc' panicked at 'No counters provided the source_hash for function: + 33| | Instance { + 34| | def: Item(WithOptConstParam { + 35| | did: DefId(0:101 ~ autocfg[c44a]::version::{impl#2}::partial_cmp), + 36| | const_param_did: None + 37| | }), + 38| | substs: [] + 39| | }' + 40| |The `PartialOrd` derived by `Version` happened to generate a MIR that generated coverage + 41| |without a code region associated with any `Counter`. Code regions were associated with at least + 42| |one expression, which is allowed, but the `function_source_hash` was only passed to the codegen + 43| |(coverage mapgen) phase from a `Counter`s code region. A new method was added to pass the + 44| |`function_source_hash` without a code region, if necessary. + 45| | + 46| |*/ + 47| | + 48| |// FIXME(#79626): The derived traits get coverage, which is great, but some of the traits appear + 49| |// to get two coverage execution counts at different positions: + 50| |// + 51| |// ```text + 52| |// 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] + 53| |// ^0 ^0 ^0 ^0 ^1 ^0 ^0^0 + 54| |// ```text + 55| |// + 56| |// `PartialEq`, `PartialOrd`, and `Ord` (and possibly `Eq`, if the trait name was longer than 2 + 57| |// characters) have counts at their first and last characters. + 58| |// + 59| |// Why is this? Why does `PartialOrd` have two values (1 and 0)? This must mean we are checking + 60| |// distinct coverages, so maybe we don't want to eliminate one of them. Should we merge them? + 61| |// If merged, do we lose some information? + diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.simple_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_loop.txt similarity index 75% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.simple_loop.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_loop.txt index 064930dd75c93..feb83bad674d0 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.simple_loop.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_loop.txt @@ -1,14 +1,14 @@ 1| |#![allow(unused_assignments)] 2| | - 3| |fn main() { - 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| | // dependent conditions. + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. 7| 1| let is_true = std::env::args().len() == 1; 8| 1| 9| 1| let mut countdown = 0; - 10| | - 11| | if + 10| 1| + 11| 1| if 12| 1| is_true 13| 1| { 14| 1| countdown @@ -27,11 +27,11 @@ 26| | { 27| 1| break 28| | ; - 29| | } + 29| 10| } 30| 10| countdown 31| 10| -= 32| 10| 1 33| | ; - 34| 1| } + 34| | } 35| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.simple_match.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt similarity index 80% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.simple_match.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt index 1f7e71d3eb0e7..81b4c090a46c0 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.simple_match.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt @@ -1,9 +1,9 @@ - 1| |#![allow(unused_assignments)] + 1| |#![allow(unused_assignments, unused_variables)] 2| | - 3| |fn main() { - 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| | // dependent conditions. + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. 7| 1| let is_true = std::env::args().len() == 1; 8| 1| 9| 1| let mut countdown = 1; @@ -27,7 +27,6 @@ 26| 2| x 27| 2| < 28| 2| 1 - ^1 29| | => 30| 1| { 31| 1| z = countdown @@ -41,6 +40,6 @@ 39| | => 40| 1| {} 41| | } - 42| 3| } + 42| | } 43| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.tight_inf_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt similarity index 62% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.tight_inf_loop.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt index e02eac03a6b15..5adeef7d0850b 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.tight_inf_loop.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt @@ -1,6 +1,6 @@ - 1| |fn main() { + 1| 1|fn main() { 2| 1| if false { 3| | loop {} - 4| | } + 4| 1| } 5| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt similarity index 87% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.try_error_result.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt index 6b3a8c39c6338..c9ebffde039d8 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.try_error_result.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt @@ -1,7 +1,7 @@ 1| |#![allow(unused_assignments)] 2| |// expect-exit-status-1 3| | - 4| |fn call(return_error: bool) -> Result<(),()> { + 4| 6|fn call(return_error: bool) -> Result<(),()> { 5| 6| if return_error { 6| 1| Err(()) 7| | } else { @@ -9,7 +9,7 @@ 9| | } 10| 6|} 11| | - 12| |fn main() -> Result<(),()> { + 12| 1|fn main() -> Result<(),()> { 13| 1| let mut 14| 1| countdown = 10 15| | ; @@ -31,8 +31,8 @@ 31| | { 32| 5| call(/*return_error=*/ false)?; ^0 - 33| 5| } - 34| 5| } + 33| | } + 34| | } 35| 0| Ok(()) 36| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt new file mode 100644 index 0000000000000..4c03e950af029 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -0,0 +1,142 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |use std::fmt::Debug; + 4| | + 5| 1|pub fn used_function() { + 6| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 7| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 8| | // dependent conditions. + 9| 1| let is_true = std::env::args().len() == 1; + 10| 1| let mut countdown = 0; + 11| 1| if is_true { + 12| 1| countdown = 10; + 13| 1| } + ^0 + 14| 1| use_this_lib_crate(); + 15| 1|} + 16| | + 17| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { + 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + 19| 2|} + ------------------ + | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { + | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | 19| 1|} + ------------------ + | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { + | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | 19| 1|} + ------------------ + 20| | + 21| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + 23| 2|} + ------------------ + | used_crate::used_only_from_this_lib_crate_generic_function::>: + | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | 23| 1|} + ------------------ + | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | 23| 1|} + ------------------ + 24| | + 25| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + 26| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + 27| 2|} + ------------------ + | used_crate::used_from_bin_crate_and_lib_crate_generic_function::>: + | 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 27| 1|} + ------------------ + | used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>: + | 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 27| 1|} + ------------------ + 28| | + 29| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + 30| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + 31| 2|} + 32| | + 33| 0|pub fn unused_generic_function(arg: T) { + 34| 0| println!("unused_generic_function with {:?}", arg); + 35| 0|} + 36| | + 37| 0|pub fn unused_function() { + 38| 0| let is_true = std::env::args().len() == 1; + 39| 0| let mut countdown = 2; + 40| 0| if !is_true { + 41| 0| countdown = 20; + 42| 0| } + 43| 0|} + 44| | + 45| 0|fn unused_private_function() { + 46| 0| let is_true = std::env::args().len() == 1; + 47| 0| let mut countdown = 2; + 48| 0| if !is_true { + 49| 0| countdown = 20; + 50| 0| } + 51| 0|} + 52| | + 53| 1|fn use_this_lib_crate() { + 54| 1| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + 55| 1| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + 56| 1| "used from library used_crate.rs", + 57| 1| ); + 58| 1| let some_vec = vec![5, 6, 7, 8]; + 59| 1| used_only_from_this_lib_crate_generic_function(some_vec); + 60| 1| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); + 61| 1|} + ------------------ + | Unexecuted instantiation: used_crate::use_this_lib_crate + ------------------ + 62| | + 63| |// FIXME(#79651): `used_from_bin_crate_and_lib_crate_generic_function()` is covered and executed + 64| |// `2` times, but the coverage output also shows (at the bottom of the coverage report): + 65| |// ------------------ + 66| |// | Unexecuted instantiation: + 67| |// ------------------ + 68| |// + 69| |// Note, the function name shown in the error seems to change depending on the structure of the + 70| |// code, for some reason, including: + 71| |// + 72| |// * used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str> + 73| |// * used_crate::use_this_lib_crate + 74| |// + 75| |// The `Unexecuted instantiation` error may be related to more than one generic function. Since the + 76| |// reporting is not consistent, it may not be obvious if there are multiple problems here; however, + 77| |// `used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>` (which I have seen + 78| |// with this error) is the only generic function missing instantiaion coverage counts. + 79| |// + 80| |// The `&str` variant was called from within this `lib` crate, and the `bin` crate also calls this + 81| |// function, but with `T` type `&Vec`. + 82| |// + 83| |// I believe the reason is that one or both crates are generating `Zero` counters for what it + 84| |// believes are "Unreachable" instantiations, but those instantiations are counted from the + 85| |// coverage map in the other crate. + 86| |// + 87| |// See `add_unreachable_coverage()` in `mapgen.rs` for more on how these `Zero` counters are added + 88| |// for what the funciton believes are `DefId`s that did not get codegenned. I suspect the issue + 89| |// may be related to this process, but this needs to be confirmed. It may not be possible to know + 90| |// for sure if a function is truly unused and should be reported with `Zero` coverage if it may + 91| |// still get used from an external crate. (Something to look at: If the `DefId` in MIR corresponds + 92| |// _only_ to the generic function without type parameters, is the `DefId` in the codegenned set, + 93| |// instantiated with one of the type parameters (in either or both crates) a *different* `DefId`? + 94| |// If so, `add_unreachable_coverage()` would assume the MIR `DefId` was uncovered, and would add + 95| |// unreachable coverage. + 96| |// + 97| |// I didn't think they could be different, but if they can, we would need to find the `DefId` for + 98| |// the generic function MIR and include it in the set of "codegenned" DefIds if any instantiation + 99| |// of that generic function does exist. + 100| |// + 101| |// Note, however, for `used_with_same_type_from_bin_crate_and_lib_crate_generic_function()` both + 102| |// crates use this function with the same type variant. The function does not have multiple + 103| |// instantiations, so the coverage analysis is not confused. No "Unexecuted instantiations" errors + 104| |// are reported. + diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while.txt similarity index 80% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while.txt index 194325b6b9eca..efa7d083f0c6f 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while.txt @@ -1,4 +1,4 @@ - 1| |fn main() { + 1| 1|fn main() { 2| 1| let num = 9; 3| 1| while num >= 10 { 4| 0| } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while_early_ret.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while_early_ret.txt similarity index 77% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while_early_ret.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while_early_ret.txt index 26041136d2f4c..d19afc0de61d3 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while_early_ret.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while_early_ret.txt @@ -1,7 +1,7 @@ 1| |#![allow(unused_assignments)] 2| |// expect-exit-status-1 3| | - 4| |fn main() -> Result<(),u8> { + 4| 1|fn main() -> Result<(),u8> { 5| 1| let mut countdown = 10; 6| | while 7| 7| countdown @@ -26,7 +26,7 @@ 26| 1| Err(1) 27| | } 28| | ; - 29| | } + 29| 6| } 30| 6| countdown 31| 6| -= 32| 6| 1 @@ -40,9 +40,4 @@ 40| |// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program 41| |// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical 42| |// to the coverage test for early returns, but this is a limitation that should be fixed. - 43| |// - 44| |// FIXME(richkadel): Consider creating a new tests for coverage when calling `std::process::exit()`, - 45| |// move the `ISSUE` comment to that test, and implement a new test directive that supports skipping - 46| |// coverage tests when targeting specific platforms (at least skipping Windows, or MSVC if the - 47| |// problem exists on MSVC only). diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt new file mode 100644 index 0000000000000..6e2f23ee77b8d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt @@ -0,0 +1,38 @@ + 1| |#![feature(generators, generator_trait)] + 2| |#![allow(unused_assignments)] + 3| | + 4| |use std::ops::{Generator, GeneratorState}; + 5| |use std::pin::Pin; + 6| | + 7| 1|fn main() { + 8| 1| let mut generator = || { + 9| 1| yield 1; + 10| 1| return "foo" + 11| 1| }; + 12| | + 13| 1| match Pin::new(&mut generator).resume(()) { + 14| 1| GeneratorState::Yielded(1) => {} + 15| 0| _ => panic!("unexpected value from resume"), + 16| | } + 17| 1| match Pin::new(&mut generator).resume(()) { + 18| 1| GeneratorState::Complete("foo") => {} + 19| 0| _ => panic!("unexpected value from resume"), + 20| | } + 21| | + 22| 1| let mut generator = || { + 23| 1| yield 1; + 24| 1| yield 2; + 25| 0| yield 3; + 26| 0| return "foo" + 27| 0| }; + 28| | + 29| 1| match Pin::new(&mut generator).resume(()) { + 30| 1| GeneratorState::Yielded(1) => {} + 31| 0| _ => panic!("unexpected value from resume"), + 32| | } + 33| 1| match Pin::new(&mut generator).resume(()) { + 34| 1| GeneratorState::Yielded(2) => {} + 35| 0| _ => panic!("unexpected value from resume"), + 36| | } + 37| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.abort.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.abort.txt new file mode 100644 index 0000000000000..cbf7462eba5e6 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.abort.txt @@ -0,0 +1,67 @@ +Counter in file 0 14:1 -> 15:27, #1 +Counter in file 0 16:11 -> 16:24, (#1 + (#2 + #3)) +Counter in file 0 17:12 -> 17:25, ((#1 + (#2 + #3)) - #4) +Counter in file 0 17:26 -> 19:10, #5 +Counter in file 0 19:10 -> 19:11, (((#1 + (#2 + #3)) - #4) - #5) +Counter in file 0 21:12 -> 21:25, (#5 + (((#1 + (#2 + #3)) - #4) - #5)) +Counter in file 0 21:26 -> 21:49, #6 +Counter in file 0 21:49 -> 21:50, ((#5 + (((#1 + (#2 + #3)) - #4) - #5)) - #6) +Counter in file 0 25:12 -> 25:25, (#6 + ((#5 + (((#1 + (#2 + #3)) - #4) - #5)) - #6)) +Counter in file 0 25:26 -> 25:49, #2 +Counter in file 0 25:49 -> 25:50, #3 +Counter in file 0 26:9 -> 26:23, (#2 + #3) +Counter in file 0 28:5 -> 29:2, #4 +Counter in file 0 5:1 -> 5:36, #1 +Counter in file 0 6:8 -> 6:20, (#1 + 0) +Counter in file 0 7:9 -> 8:37, #2 +Counter in file 0 9:12 -> 12:2, (#1 - #2) +Emitting segments for file: ../coverage/abort.rs +Combined regions: + 5:1 -> 5:36 (count=12) + 6:8 -> 6:20 (count=12) + 7:9 -> 8:37 (count=0) + 9:12 -> 12:2 (count=12) + 14:1 -> 15:27 (count=1) + 16:11 -> 16:24 (count=11) + 17:12 -> 17:25 (count=10) + 17:26 -> 19:10 (count=4) + 19:10 -> 19:11 (count=6) + 21:12 -> 21:25 (count=10) + 21:26 -> 21:49 (count=4) + 21:49 -> 21:50 (count=6) + 25:12 -> 25:25 (count=10) + 25:26 -> 25:49 (count=4) + 25:49 -> 25:50 (count=6) + 26:9 -> 26:23 (count=10) + 28:5 -> 29:2 (count=1) +Segment at 5:1 (count = 12), RegionEntry +Segment at 5:36 (count = 0), Skipped +Segment at 6:8 (count = 12), RegionEntry +Segment at 6:20 (count = 0), Skipped +Segment at 7:9 (count = 0), RegionEntry +Segment at 8:37 (count = 0), Skipped +Segment at 9:12 (count = 12), RegionEntry +Segment at 12:2 (count = 0), Skipped +Segment at 14:1 (count = 1), RegionEntry +Segment at 15:27 (count = 0), Skipped +Segment at 16:11 (count = 11), RegionEntry +Segment at 16:24 (count = 0), Skipped +Segment at 17:12 (count = 10), RegionEntry +Segment at 17:25 (count = 0), Skipped +Segment at 17:26 (count = 4), RegionEntry +Segment at 19:10 (count = 6), RegionEntry +Segment at 19:11 (count = 0), Skipped +Segment at 21:12 (count = 10), RegionEntry +Segment at 21:25 (count = 0), Skipped +Segment at 21:26 (count = 4), RegionEntry +Segment at 21:49 (count = 6), RegionEntry +Segment at 21:50 (count = 0), Skipped +Segment at 25:12 (count = 10), RegionEntry +Segment at 25:25 (count = 0), Skipped +Segment at 25:26 (count = 4), RegionEntry +Segment at 25:49 (count = 6), RegionEntry +Segment at 25:50 (count = 0), Skipped +Segment at 26:9 (count = 10), RegionEntry +Segment at 26:23 (count = 0), Skipped +Segment at 28:5 (count = 1), RegionEntry +Segment at 29:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt new file mode 100644 index 0000000000000..916ebbbcc29d3 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt @@ -0,0 +1,57 @@ +Counter in file 0 9:1 -> 10:27, #1 +Counter in file 0 11:11 -> 11:24, (#1 + (#2 + (#3 + #4))) +Counter in file 0 12:12 -> 12:26, ((#1 + (#2 + (#3 + #4))) - #5) +Counter in file 0 12:27 -> 14:10, #2 +Counter in file 0 14:19 -> 14:32, (((#1 + (#2 + (#3 + #4))) - #5) - #2) +Counter in file 0 14:33 -> 16:10, #3 +Counter in file 0 16:10 -> 16:11, #4 +Counter in file 0 17:9 -> 17:23, (#2 + (#3 + #4)) +Counter in file 0 19:5 -> 20:2, #5 +Counter in file 0 4:1 -> 4:41, #1 +Counter in file 0 5:5 -> 5:48, (#1 + 0) +Counter in file 0 6:16 -> 6:21, (#1 + 0) +Counter in file 0 6:37 -> 6:61, #2 +Counter in file 0 7:1 -> 7:2, (#1 - #2) +Emitting segments for file: ../coverage/assert.rs +Combined regions: + 4:1 -> 4:41 (count=4) + 5:5 -> 5:48 (count=4) + 6:16 -> 6:21 (count=4) + 6:37 -> 6:61 (count=1) + 7:1 -> 7:2 (count=3) + 9:1 -> 10:27 (count=1) + 11:11 -> 11:24 (count=10) + 12:12 -> 12:26 (count=10) + 12:27 -> 14:10 (count=0) + 14:19 -> 14:32 (count=10) + 14:33 -> 16:10 (count=3) + 16:10 -> 16:11 (count=6) + 17:9 -> 17:23 (count=9) + 19:5 -> 20:2 (count=0) +Segment at 4:1 (count = 4), RegionEntry +Segment at 4:41 (count = 0), Skipped +Segment at 5:5 (count = 4), RegionEntry +Segment at 5:48 (count = 0), Skipped +Segment at 6:16 (count = 4), RegionEntry +Segment at 6:21 (count = 0), Skipped +Segment at 6:37 (count = 1), RegionEntry +Segment at 6:61 (count = 0), Skipped +Segment at 7:1 (count = 3), RegionEntry +Segment at 7:2 (count = 0), Skipped +Segment at 9:1 (count = 1), RegionEntry +Segment at 10:27 (count = 0), Skipped +Segment at 11:11 (count = 10), RegionEntry +Segment at 11:24 (count = 0), Skipped +Segment at 12:12 (count = 10), RegionEntry +Segment at 12:26 (count = 0), Skipped +Segment at 12:27 (count = 0), RegionEntry +Segment at 14:10 (count = 0), Skipped +Segment at 14:19 (count = 10), RegionEntry +Segment at 14:32 (count = 0), Skipped +Segment at 14:33 (count = 3), RegionEntry +Segment at 16:10 (count = 6), RegionEntry +Segment at 16:11 (count = 0), Skipped +Segment at 17:9 (count = 9), RegionEntry +Segment at 17:23 (count = 0), Skipped +Segment at 19:5 (count = 0), RegionEntry +Segment at 20:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt new file mode 100644 index 0000000000000..abc2d32a89795 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt @@ -0,0 +1,311 @@ +Counter in file 0 13:1 -> 13:20, #1 +Counter in file 0 15:1 -> 15:20, 0 +Counter in file 0 15:20 -> 15:21, 0 +Counter in file 0 19:1 -> 19:30, 0 +Counter in file 0 19:30 -> 19:31, 0 +Counter in file 0 21:23 -> 22:12, 0 +Counter in file 0 23:9 -> 23:10, 0 +Counter in file 0 23:14 -> 23:17, 0 +Counter in file 0 23:27 -> 23:28, 0 +Counter in file 0 23:32 -> 23:34, 0 +Counter in file 0 24:9 -> 24:10, 0 +Counter in file 0 24:14 -> 24:17, 0 +Counter in file 0 24:27 -> 24:28, 0 +Counter in file 0 24:32 -> 24:34, 0 +Counter in file 0 25:14 -> 25:16, 0 +Counter in file 0 27:1 -> 27:2, 0 +Counter in file 0 29:22 -> 32:12, 0 +Counter in file 0 33:9 -> 33:10, 0 +Counter in file 0 33:14 -> 33:19, 0 +Counter in file 0 33:26 -> 33:27, 0 +Counter in file 0 33:32 -> 33:34, 0 +Counter in file 0 34:14 -> 34:16, 0 +Counter in file 0 36:1 -> 36:2, 0 +Counter in file 0 75:1 -> 76:12, 0 +Counter in file 0 77:14 -> 77:16, 0 +Counter in file 0 78:14 -> 78:16, 0 +Counter in file 0 79:14 -> 79:16, 0 +Counter in file 0 81:1 -> 81:2, 0 +Counter in file 0 91:25 -> 91:34, 0 +Counter in file 0 5:1 -> 5:25, #1 +Counter in file 0 5:25 -> 6:14, #1 +Counter in file 0 7:9 -> 7:10, #2 +Counter in file 0 9:9 -> 9:10, (#1 - #2) +Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) +Counter in file 0 21:1 -> 21:23, #1 +Counter in file 0 67:5 -> 67:23, #1 +Counter in file 0 38:1 -> 38:19, #1 +Counter in file 0 29:1 -> 29:22, #1 +Counter in file 0 93:1 -> 101:2, #1 +Counter in file 0 91:1 -> 91:25, #1 +Counter in file 0 38:19 -> 42:12, #1 +Counter in file 0 43:9 -> 43:10, #3 +Counter in file 0 43:14 -> 43:18, (#1 + 0) +Counter in file 0 43:28 -> 43:33, #2 +Counter in file 0 43:39 -> 43:42, (#3 + 0) +Counter in file 0 44:9 -> 44:10, #6 +Counter in file 0 44:14 -> 44:17, #4 +Counter in file 0 44:27 -> 44:32, #8 +Counter in file 0 44:36 -> 44:38, (#6 + 0) +Counter in file 0 45:14 -> 45:16, #7 +Counter in file 0 47:1 -> 47:2, (#5 + (#6 + #7)) +Counter in file 0 51:5 -> 52:18, #1 +Counter in file 0 53:13 -> 53:14, #2 +Counter in file 0 63:13 -> 63:14, (#1 - #2) +Counter in file 0 65:5 -> 65:6, (#2 + (#1 - #2)) +Counter in file 0 13:20 -> 13:21, #1 +Counter in file 0 49:1 -> 68:12, #1 +Counter in file 0 69:9 -> 69:10, #2 +Counter in file 0 69:14 -> 69:27, (#1 + 0) +Counter in file 0 69:31 -> 69:39, (#2 + 0) +Counter in file 0 70:9 -> 70:10, #3 +Counter in file 0 70:14 -> 70:26, #5 +Counter in file 0 70:30 -> 70:32, (#3 + 0) +Counter in file 0 71:14 -> 71:16, #4 +Counter in file 0 73:1 -> 73:2, (#2 + (#3 + #4)) +Counter in file 0 83:1 -> 84:12, #1 +Counter in file 0 85:14 -> 85:16, (#1 - (#3 + #2)) +Counter in file 0 86:14 -> 86:16, #2 +Counter in file 0 87:14 -> 87:16, #3 +Counter in file 0 89:1 -> 89:2, (#3 + (#2 + (#1 - (#3 + #2)))) +Counter in file 0 17:1 -> 17:20, #1 +Counter in file 0 17:20 -> 17:21, #1 +Counter in file 0 66:5 -> 66:23, #1 +Counter in file 0 17:9 -> 17:10, #1 +Counter in file 0 17:9 -> 17:10, #1 +Counter in file 0 117:17 -> 117:19, #1 +Counter in file 0 17:9 -> 17:10, #1 +Counter in file 0 110:5 -> 120:54, #1 +Counter in file 0 123:32 -> 123:35, ((#1 + #2) - #2) +Counter in file 0 123:39 -> 123:73, (#1 + #2) +Counter in file 0 124:23 -> 124:26, (((#1 + #2) - #2) + 0) +Counter in file 0 125:14 -> 125:15, #2 +Counter in file 0 127:5 -> 127:6, (((#1 + #2) - #2) + 0) +Emitting segments for file: ../coverage/async.rs +Combined regions: + 5:1 -> 5:25 (count=1) + 5:25 -> 6:14 (count=1) + 7:9 -> 7:10 (count=1) + 9:9 -> 9:10 (count=0) + 11:1 -> 11:2 (count=1) + 13:1 -> 13:20 (count=0) + 15:1 -> 15:20 (count=0) + 15:20 -> 15:21 (count=0) + 17:1 -> 17:20 (count=1) + 17:20 -> 17:21 (count=1) + 19:1 -> 19:30 (count=0) + 19:30 -> 19:31 (count=0) + 21:1 -> 21:23 (count=1) + 21:23 -> 22:12 (count=0) + 23:9 -> 23:10 (count=0) + 23:14 -> 23:17 (count=0) + 23:27 -> 23:28 (count=0) + 23:32 -> 23:34 (count=0) + 24:9 -> 24:10 (count=0) + 24:14 -> 24:17 (count=0) + 24:27 -> 24:28 (count=0) + 24:32 -> 24:34 (count=0) + 25:14 -> 25:16 (count=0) + 27:1 -> 27:2 (count=0) + 29:1 -> 29:22 (count=1) + 29:22 -> 32:12 (count=0) + 33:9 -> 33:10 (count=0) + 33:14 -> 33:19 (count=0) + 33:26 -> 33:27 (count=0) + 33:32 -> 33:34 (count=0) + 34:14 -> 34:16 (count=0) + 36:1 -> 36:2 (count=0) + 38:1 -> 38:19 (count=1) + 38:19 -> 42:12 (count=1) + 43:9 -> 43:10 (count=0) + 43:14 -> 43:18 (count=1) + 43:28 -> 43:33 (count=1) + 43:39 -> 43:42 (count=0) + 44:9 -> 44:10 (count=0) + 44:14 -> 44:17 (count=1) + 44:27 -> 44:32 (count=1) + 44:36 -> 44:38 (count=0) + 45:14 -> 45:16 (count=1) + 47:1 -> 47:2 (count=1) + 49:1 -> 68:12 (count=1) + 51:5 -> 52:18 (count=1) + 53:13 -> 53:14 (count=0) + 63:13 -> 63:14 (count=1) + 65:5 -> 65:6 (count=1) + 67:5 -> 67:23 (count=1) + 69:9 -> 69:10 (count=0) + 69:14 -> 69:27 (count=1) + 69:31 -> 69:39 (count=0) + 70:9 -> 70:10 (count=0) + 70:14 -> 70:26 (count=1) + 70:30 -> 70:32 (count=0) + 71:14 -> 71:16 (count=1) + 73:1 -> 73:2 (count=1) + 75:1 -> 76:12 (count=0) + 77:14 -> 77:16 (count=0) + 78:14 -> 78:16 (count=0) + 79:14 -> 79:16 (count=0) + 81:1 -> 81:2 (count=0) + 83:1 -> 84:12 (count=1) + 85:14 -> 85:16 (count=0) + 86:14 -> 86:16 (count=0) + 87:14 -> 87:16 (count=1) + 89:1 -> 89:2 (count=1) + 91:1 -> 91:25 (count=1) + 91:25 -> 91:34 (count=0) + 93:1 -> 101:2 (count=1) + 110:5 -> 120:54 (count=1) + 117:17 -> 117:19 (count=1) + 123:32 -> 123:35 (count=1) + 123:39 -> 123:73 (count=1) + 124:23 -> 124:26 (count=1) + 125:14 -> 125:15 (count=0) + 127:5 -> 127:6 (count=1) +Segment at 5:1 (count = 1), RegionEntry +Segment at 5:25 (count = 1), RegionEntry +Segment at 6:14 (count = 0), Skipped +Segment at 7:9 (count = 1), RegionEntry +Segment at 7:10 (count = 0), Skipped +Segment at 9:9 (count = 0), RegionEntry +Segment at 9:10 (count = 0), Skipped +Segment at 11:1 (count = 1), RegionEntry +Segment at 11:2 (count = 0), Skipped +Segment at 13:1 (count = 0), RegionEntry +Segment at 13:20 (count = 0), Skipped +Segment at 15:1 (count = 0), RegionEntry +Segment at 15:20 (count = 0), RegionEntry +Segment at 15:21 (count = 0), Skipped +Segment at 17:1 (count = 1), RegionEntry +Segment at 17:20 (count = 1), RegionEntry +Segment at 17:21 (count = 0), Skipped +Segment at 19:1 (count = 0), RegionEntry +Segment at 19:30 (count = 0), RegionEntry +Segment at 19:31 (count = 0), Skipped +Segment at 21:1 (count = 1), RegionEntry +Segment at 21:23 (count = 0), RegionEntry +Segment at 22:12 (count = 0), Skipped +Segment at 23:9 (count = 0), RegionEntry +Segment at 23:10 (count = 0), Skipped +Segment at 23:14 (count = 0), RegionEntry +Segment at 23:17 (count = 0), Skipped +Segment at 23:27 (count = 0), RegionEntry +Segment at 23:28 (count = 0), Skipped +Segment at 23:32 (count = 0), RegionEntry +Segment at 23:34 (count = 0), Skipped +Segment at 24:9 (count = 0), RegionEntry +Segment at 24:10 (count = 0), Skipped +Segment at 24:14 (count = 0), RegionEntry +Segment at 24:17 (count = 0), Skipped +Segment at 24:27 (count = 0), RegionEntry +Segment at 24:28 (count = 0), Skipped +Segment at 24:32 (count = 0), RegionEntry +Segment at 24:34 (count = 0), Skipped +Segment at 25:14 (count = 0), RegionEntry +Segment at 25:16 (count = 0), Skipped +Segment at 27:1 (count = 0), RegionEntry +Segment at 27:2 (count = 0), Skipped +Segment at 29:1 (count = 1), RegionEntry +Segment at 29:22 (count = 0), RegionEntry +Segment at 32:12 (count = 0), Skipped +Segment at 33:9 (count = 0), RegionEntry +Segment at 33:10 (count = 0), Skipped +Segment at 33:14 (count = 0), RegionEntry +Segment at 33:19 (count = 0), Skipped +Segment at 33:26 (count = 0), RegionEntry +Segment at 33:27 (count = 0), Skipped +Segment at 33:32 (count = 0), RegionEntry +Segment at 33:34 (count = 0), Skipped +Segment at 34:14 (count = 0), RegionEntry +Segment at 34:16 (count = 0), Skipped +Segment at 36:1 (count = 0), RegionEntry +Segment at 36:2 (count = 0), Skipped +Segment at 38:1 (count = 1), RegionEntry +Segment at 38:19 (count = 1), RegionEntry +Segment at 42:12 (count = 0), Skipped +Segment at 43:9 (count = 0), RegionEntry +Segment at 43:10 (count = 0), Skipped +Segment at 43:14 (count = 1), RegionEntry +Segment at 43:18 (count = 0), Skipped +Segment at 43:28 (count = 1), RegionEntry +Segment at 43:33 (count = 0), Skipped +Segment at 43:39 (count = 0), RegionEntry +Segment at 43:42 (count = 0), Skipped +Segment at 44:9 (count = 0), RegionEntry +Segment at 44:10 (count = 0), Skipped +Segment at 44:14 (count = 1), RegionEntry +Segment at 44:17 (count = 0), Skipped +Segment at 44:27 (count = 1), RegionEntry +Segment at 44:32 (count = 0), Skipped +Segment at 44:36 (count = 0), RegionEntry +Segment at 44:38 (count = 0), Skipped +Segment at 45:14 (count = 1), RegionEntry +Segment at 45:16 (count = 0), Skipped +Segment at 47:1 (count = 1), RegionEntry +Segment at 47:2 (count = 0), Skipped +Segment at 49:1 (count = 1), RegionEntry +Segment at 51:5 (count = 1), RegionEntry +Segment at 52:18 (count = 1) +Segment at 53:13 (count = 0), RegionEntry +Segment at 53:14 (count = 1) +Segment at 63:13 (count = 1), RegionEntry +Segment at 63:14 (count = 1) +Segment at 65:5 (count = 1), RegionEntry +Segment at 65:6 (count = 1) +Segment at 67:5 (count = 1), RegionEntry +Segment at 67:23 (count = 1) +Segment at 68:12 (count = 0), Skipped +Segment at 69:9 (count = 0), RegionEntry +Segment at 69:10 (count = 0), Skipped +Segment at 69:14 (count = 1), RegionEntry +Segment at 69:27 (count = 0), Skipped +Segment at 69:31 (count = 0), RegionEntry +Segment at 69:39 (count = 0), Skipped +Segment at 70:9 (count = 0), RegionEntry +Segment at 70:10 (count = 0), Skipped +Segment at 70:14 (count = 1), RegionEntry +Segment at 70:26 (count = 0), Skipped +Segment at 70:30 (count = 0), RegionEntry +Segment at 70:32 (count = 0), Skipped +Segment at 71:14 (count = 1), RegionEntry +Segment at 71:16 (count = 0), Skipped +Segment at 73:1 (count = 1), RegionEntry +Segment at 73:2 (count = 0), Skipped +Segment at 75:1 (count = 0), RegionEntry +Segment at 76:12 (count = 0), Skipped +Segment at 77:14 (count = 0), RegionEntry +Segment at 77:16 (count = 0), Skipped +Segment at 78:14 (count = 0), RegionEntry +Segment at 78:16 (count = 0), Skipped +Segment at 79:14 (count = 0), RegionEntry +Segment at 79:16 (count = 0), Skipped +Segment at 81:1 (count = 0), RegionEntry +Segment at 81:2 (count = 0), Skipped +Segment at 83:1 (count = 1), RegionEntry +Segment at 84:12 (count = 0), Skipped +Segment at 85:14 (count = 0), RegionEntry +Segment at 85:16 (count = 0), Skipped +Segment at 86:14 (count = 0), RegionEntry +Segment at 86:16 (count = 0), Skipped +Segment at 87:14 (count = 1), RegionEntry +Segment at 87:16 (count = 0), Skipped +Segment at 89:1 (count = 1), RegionEntry +Segment at 89:2 (count = 0), Skipped +Segment at 91:1 (count = 1), RegionEntry +Segment at 91:25 (count = 0), RegionEntry +Segment at 91:34 (count = 0), Skipped +Segment at 93:1 (count = 1), RegionEntry +Segment at 101:2 (count = 0), Skipped +Segment at 110:5 (count = 1), RegionEntry +Segment at 117:17 (count = 1), RegionEntry +Segment at 117:19 (count = 1) +Segment at 120:54 (count = 0), Skipped +Segment at 123:32 (count = 1), RegionEntry +Segment at 123:35 (count = 0), Skipped +Segment at 123:39 (count = 1), RegionEntry +Segment at 123:73 (count = 0), Skipped +Segment at 124:23 (count = 1), RegionEntry +Segment at 124:26 (count = 0), Skipped +Segment at 125:14 (count = 0), RegionEntry +Segment at 125:15 (count = 0), Skipped +Segment at 127:5 (count = 1), RegionEntry +Segment at 127:6 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.closure.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.closure.txt new file mode 100644 index 0000000000000..1aacac0ed2515 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.closure.txt @@ -0,0 +1,153 @@ +Counter in file 0 98:5 -> 100:20, #1 +Counter in file 0 100:21 -> 102:10, #2 +Counter in file 0 102:10 -> 102:11, (#1 - #2) +Counter in file 0 103:9 -> 104:6, (#2 + (#1 - #2)) +Counter in file 0 123:5 -> 124:20, 0 +Counter in file 0 124:21 -> 126:10, 0 +Counter in file 0 126:10 -> 126:11, 0 +Counter in file 0 127:9 -> 128:6, 0 +Counter in file 0 131:53 -> 131:67, 0 +Counter in file 0 141:59 -> 141:85, 0 +Counter in file 0 143:56 -> 145:6, 0 +Counter in file 0 149:7 -> 149:33, 0 +Counter in file 0 153:7 -> 153:33, 0 +Counter in file 0 3:1 -> 18:13, #1 +Counter in file 0 25:14 -> 33:9, (#1 + 0) +Counter in file 0 40:6 -> 60:13, (#1 + 0) +Counter in file 0 67:14 -> 75:9, (#1 + 0) +Counter in file 0 82:6 -> 97:9, (#1 + 0) +Counter in file 0 104:6 -> 120:9, (#1 + 0) +Counter in file 0 128:6 -> 131:33, (#1 + 0) +Counter in file 0 131:67 -> 136:33, (#1 + 0) +Counter in file 0 136:75 -> 141:39, (#1 + 0) +Counter in file 0 141:85 -> 143:36, (#1 + 0) +Counter in file 0 145:6 -> 147:36, (#1 + 0) +Counter in file 0 149:33 -> 151:43, (#1 + 0) +Counter in file 0 153:33 -> 155:2, (#1 + 0) +Counter in file 0 61:13 -> 63:28, #1 +Counter in file 0 63:29 -> 65:18, #2 +Counter in file 0 65:18 -> 65:19, (#1 - #2) +Counter in file 0 66:17 -> 67:14, (#2 + (#1 - #2)) +Counter in file 0 76:5 -> 78:20, #1 +Counter in file 0 78:21 -> 80:10, #2 +Counter in file 0 80:10 -> 80:11, (#1 - #2) +Counter in file 0 81:9 -> 82:6, (#2 + (#1 - #2)) +Counter in file 0 34:5 -> 36:20, #1 +Counter in file 0 36:21 -> 38:10, #2 +Counter in file 0 38:10 -> 38:11, (#1 - #2) +Counter in file 0 39:9 -> 40:6, (#2 + (#1 - #2)) +Counter in file 0 19:13 -> 21:28, #1 +Counter in file 0 21:29 -> 23:18, #2 +Counter in file 0 23:18 -> 23:19, (#1 - #2) +Counter in file 0 24:17 -> 25:14, (#2 + (#1 - #2)) +Emitting segments for file: ../coverage/closure.rs +Combined regions: + 3:1 -> 18:13 (count=1) + 19:13 -> 21:28 (count=0) + 21:29 -> 23:18 (count=0) + 23:18 -> 23:19 (count=0) + 24:17 -> 25:14 (count=0) + 25:14 -> 33:9 (count=1) + 34:5 -> 36:20 (count=0) + 36:21 -> 38:10 (count=0) + 38:10 -> 38:11 (count=0) + 39:9 -> 40:6 (count=0) + 40:6 -> 60:13 (count=1) + 61:13 -> 63:28 (count=1) + 63:29 -> 65:18 (count=0) + 65:18 -> 65:19 (count=1) + 66:17 -> 67:14 (count=1) + 67:14 -> 75:9 (count=1) + 76:5 -> 78:20 (count=1) + 78:21 -> 80:10 (count=0) + 80:10 -> 80:11 (count=1) + 81:9 -> 82:6 (count=1) + 82:6 -> 97:9 (count=1) + 98:5 -> 100:20 (count=5) + 100:21 -> 102:10 (count=0) + 102:10 -> 102:11 (count=5) + 103:9 -> 104:6 (count=5) + 104:6 -> 120:9 (count=1) + 123:5 -> 124:20 (count=0) + 124:21 -> 126:10 (count=0) + 126:10 -> 126:11 (count=0) + 127:9 -> 128:6 (count=0) + 128:6 -> 131:33 (count=1) + 131:53 -> 131:67 (count=0) + 131:67 -> 136:33 (count=1) + 136:75 -> 141:39 (count=1) + 141:59 -> 141:85 (count=0) + 141:85 -> 143:36 (count=1) + 143:56 -> 145:6 (count=0) + 145:6 -> 147:36 (count=1) + 149:7 -> 149:33 (count=0) + 149:33 -> 151:43 (count=1) + 153:7 -> 153:33 (count=0) + 153:33 -> 155:2 (count=1) +Segment at 3:1 (count = 1), RegionEntry +Segment at 18:13 (count = 0), Skipped +Segment at 19:13 (count = 0), RegionEntry +Segment at 21:28 (count = 0), Skipped +Segment at 21:29 (count = 0), RegionEntry +Segment at 23:18 (count = 0), RegionEntry +Segment at 23:19 (count = 0), Skipped +Segment at 24:17 (count = 0), RegionEntry +Segment at 25:14 (count = 1), RegionEntry +Segment at 33:9 (count = 0), Skipped +Segment at 34:5 (count = 0), RegionEntry +Segment at 36:20 (count = 0), Skipped +Segment at 36:21 (count = 0), RegionEntry +Segment at 38:10 (count = 0), RegionEntry +Segment at 38:11 (count = 0), Skipped +Segment at 39:9 (count = 0), RegionEntry +Segment at 40:6 (count = 1), RegionEntry +Segment at 60:13 (count = 0), Skipped +Segment at 61:13 (count = 1), RegionEntry +Segment at 63:28 (count = 0), Skipped +Segment at 63:29 (count = 0), RegionEntry +Segment at 65:18 (count = 1), RegionEntry +Segment at 65:19 (count = 0), Skipped +Segment at 66:17 (count = 1), RegionEntry +Segment at 67:14 (count = 1), RegionEntry +Segment at 75:9 (count = 0), Skipped +Segment at 76:5 (count = 1), RegionEntry +Segment at 78:20 (count = 0), Skipped +Segment at 78:21 (count = 0), RegionEntry +Segment at 80:10 (count = 1), RegionEntry +Segment at 80:11 (count = 0), Skipped +Segment at 81:9 (count = 1), RegionEntry +Segment at 82:6 (count = 1), RegionEntry +Segment at 97:9 (count = 0), Skipped +Segment at 98:5 (count = 5), RegionEntry +Segment at 100:20 (count = 0), Skipped +Segment at 100:21 (count = 0), RegionEntry +Segment at 102:10 (count = 5), RegionEntry +Segment at 102:11 (count = 0), Skipped +Segment at 103:9 (count = 5), RegionEntry +Segment at 104:6 (count = 1), RegionEntry +Segment at 120:9 (count = 0), Skipped +Segment at 123:5 (count = 0), RegionEntry +Segment at 124:20 (count = 0), Skipped +Segment at 124:21 (count = 0), RegionEntry +Segment at 126:10 (count = 0), RegionEntry +Segment at 126:11 (count = 0), Skipped +Segment at 127:9 (count = 0), RegionEntry +Segment at 128:6 (count = 1), RegionEntry +Segment at 131:33 (count = 0), Skipped +Segment at 131:53 (count = 0), RegionEntry +Segment at 131:67 (count = 1), RegionEntry +Segment at 136:33 (count = 0), Skipped +Segment at 136:75 (count = 1), RegionEntry +Segment at 141:39 (count = 0), Skipped +Segment at 141:59 (count = 0), RegionEntry +Segment at 141:85 (count = 1), RegionEntry +Segment at 143:36 (count = 0), Skipped +Segment at 143:56 (count = 0), RegionEntry +Segment at 145:6 (count = 1), RegionEntry +Segment at 147:36 (count = 0), Skipped +Segment at 149:7 (count = 0), RegionEntry +Segment at 149:33 (count = 1), RegionEntry +Segment at 151:43 (count = 0), Skipped +Segment at 153:7 (count = 0), RegionEntry +Segment at 153:33 (count = 1), RegionEntry +Segment at 155:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.conditions.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.conditions.txt new file mode 100644 index 0000000000000..3a9c6a9b92e98 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.conditions.txt @@ -0,0 +1,253 @@ +Counter in file 0 3:1 -> 3:11, #1 +Counter in file 0 4:9 -> 5:12, (#1 + 0) +Counter in file 0 5:13 -> 7:6, #2 +Counter in file 0 10:9 -> 10:10, (#3 + (#12 + #13)) +Counter in file 0 10:16 -> 10:29, (#2 + 0) +Counter in file 0 11:9 -> 12:10, #3 +Counter in file 0 13:15 -> 13:28, ((#2 + 0) - #3) +Counter in file 0 14:12 -> 14:25, #4 +Counter in file 0 14:29 -> 14:42, (#4 - #15) +Counter in file 0 14:46 -> 14:60, #21 +Counter in file 0 14:61 -> 16:10, #12 +Counter in file 0 16:10 -> 16:11, #13 +Counter in file 0 17:9 -> 18:18, (#12 + #13) +Counter in file 0 20:9 -> 20:15, (((#2 + 0) - #3) - #4) +Counter in file 0 23:9 -> 24:12, ((#3 + (#12 + #13)) + 0) +Counter in file 0 24:13 -> 26:6, #14 +Counter in file 0 28:8 -> 28:21, (#14 + 0) +Counter in file 0 28:22 -> 30:6, #16 +Counter in file 0 30:15 -> 30:28, ((#14 + 0) - #16) +Counter in file 0 31:12 -> 31:25, (((#14 + 0) - #16) - #11) +Counter in file 0 31:29 -> 31:42, ((((#14 + 0) - #16) - #11) - #23) +Counter in file 0 31:46 -> 31:60, #31 +Counter in file 0 31:61 -> 33:10, #18 +Counter in file 0 33:10 -> 33:11, #19 +Counter in file 0 34:9 -> 34:23, (#18 + #19) +Counter in file 0 36:9 -> 36:15, #11 +Counter in file 0 39:8 -> 39:12, (#16 + (#18 + #19)) +Counter in file 0 40:13 -> 41:16, #20 +Counter in file 0 41:17 -> 43:10, #24 +Counter in file 0 45:12 -> 45:25, (#24 + 0) +Counter in file 0 45:26 -> 47:10, #25 +Counter in file 0 48:17 -> 48:30, ((#24 + 0) - #25) +Counter in file 0 49:16 -> 49:29, (((#24 + 0) - #25) - #10) +Counter in file 0 49:33 -> 49:46, ((((#24 + 0) - #25) - #10) - #35) +Counter in file 0 49:50 -> 49:64, #40 +Counter in file 0 49:65 -> 51:14, #26 +Counter in file 0 51:14 -> 51:15, #27 +Counter in file 0 52:13 -> 52:27, (#26 + #27) +Counter in file 0 54:13 -> 54:19, #10 +Counter in file 0 59:9 -> 60:12, ((#25 + (#26 + #27)) + 0) +Counter in file 0 60:13 -> 62:6, #28 +Counter in file 0 64:9 -> 64:10, (#30 + (#33 + #34)) +Counter in file 0 64:16 -> 64:29, (#28 + 0) +Counter in file 0 64:30 -> 66:6, #30 +Counter in file 0 66:15 -> 66:28, ((#28 + 0) - #30) +Counter in file 0 67:12 -> 67:25, (((#28 + 0) - #30) - #9) +Counter in file 0 67:29 -> 67:42, ((((#28 + 0) - #30) - #9) - #36) +Counter in file 0 67:46 -> 67:60, #42 +Counter in file 0 67:61 -> 69:10, #33 +Counter in file 0 69:10 -> 69:11, #34 +Counter in file 0 70:9 -> 70:23, (#33 + #34) +Counter in file 0 72:13 -> 74:15, #9 +Counter in file 0 77:9 -> 77:10, (#5 + (#6 + #7)) +Counter in file 0 77:16 -> 77:29, ((#30 + (#33 + #34)) + 0) +Counter in file 0 77:30 -> 79:6, #5 +Counter in file 0 79:15 -> 79:28, ((#30 + (#33 + #34)) - #5) +Counter in file 0 80:12 -> 80:25, (((#30 + (#33 + #34)) - #5) - #8) +Counter in file 0 80:29 -> 80:42, ((((#30 + (#33 + #34)) - #5) - #8) - #39) +Counter in file 0 80:46 -> 80:60, #45 +Counter in file 0 80:61 -> 82:10, #6 +Counter in file 0 82:10 -> 82:11, #7 +Counter in file 0 83:9 -> 83:23, (#6 + #7) +Counter in file 0 85:9 -> 85:15, #8 +Counter in file 0 87:1 -> 87:2, ((#5 + (#6 + #7)) + (((#8 + #9) + (#10 + #11)) + (((#2 + 0) - #3) - #4))) +Emitting segments for file: ../coverage/conditions.rs +Combined regions: + 3:1 -> 3:11 (count=1) + 4:9 -> 5:12 (count=1) + 5:13 -> 7:6 (count=1) + 10:9 -> 10:10 (count=1) + 10:16 -> 10:29 (count=1) + 11:9 -> 12:10 (count=1) + 13:15 -> 13:28 (count=0) + 14:12 -> 14:25 (count=0) + 14:29 -> 14:42 (count=0) + 14:46 -> 14:60 (count=0) + 14:61 -> 16:10 (count=0) + 16:10 -> 16:11 (count=0) + 17:9 -> 18:18 (count=0) + 20:9 -> 20:15 (count=0) + 23:9 -> 24:12 (count=1) + 24:13 -> 26:6 (count=1) + 28:8 -> 28:21 (count=1) + 28:22 -> 30:6 (count=1) + 30:15 -> 30:28 (count=0) + 31:12 -> 31:25 (count=0) + 31:29 -> 31:42 (count=0) + 31:46 -> 31:60 (count=0) + 31:61 -> 33:10 (count=0) + 33:10 -> 33:11 (count=0) + 34:9 -> 34:23 (count=0) + 36:9 -> 36:15 (count=0) + 39:8 -> 39:12 (count=1) + 40:13 -> 41:16 (count=1) + 41:17 -> 43:10 (count=1) + 45:12 -> 45:25 (count=1) + 45:26 -> 47:10 (count=1) + 48:17 -> 48:30 (count=0) + 49:16 -> 49:29 (count=0) + 49:33 -> 49:46 (count=0) + 49:50 -> 49:64 (count=0) + 49:65 -> 51:14 (count=0) + 51:14 -> 51:15 (count=0) + 52:13 -> 52:27 (count=0) + 54:13 -> 54:19 (count=0) + 59:9 -> 60:12 (count=1) + 60:13 -> 62:6 (count=1) + 64:9 -> 64:10 (count=0) + 64:16 -> 64:29 (count=1) + 64:30 -> 66:6 (count=0) + 66:15 -> 66:28 (count=1) + 67:12 -> 67:25 (count=0) + 67:29 -> 67:42 (count=0) + 67:46 -> 67:60 (count=0) + 67:61 -> 69:10 (count=0) + 69:10 -> 69:11 (count=0) + 70:9 -> 70:23 (count=0) + 72:13 -> 74:15 (count=1) + 77:9 -> 77:10 (count=0) + 77:16 -> 77:29 (count=0) + 77:30 -> 79:6 (count=0) + 79:15 -> 79:28 (count=0) + 80:12 -> 80:25 (count=0) + 80:29 -> 80:42 (count=0) + 80:46 -> 80:60 (count=0) + 80:61 -> 82:10 (count=0) + 82:10 -> 82:11 (count=0) + 83:9 -> 83:23 (count=0) + 85:9 -> 85:15 (count=0) + 87:1 -> 87:2 (count=1) +Segment at 3:1 (count = 1), RegionEntry +Segment at 3:11 (count = 0), Skipped +Segment at 4:9 (count = 1), RegionEntry +Segment at 5:12 (count = 0), Skipped +Segment at 5:13 (count = 1), RegionEntry +Segment at 7:6 (count = 0), Skipped +Segment at 10:9 (count = 1), RegionEntry +Segment at 10:10 (count = 0), Skipped +Segment at 10:16 (count = 1), RegionEntry +Segment at 10:29 (count = 0), Skipped +Segment at 11:9 (count = 1), RegionEntry +Segment at 12:10 (count = 0), Skipped +Segment at 13:15 (count = 0), RegionEntry +Segment at 13:28 (count = 0), Skipped +Segment at 14:12 (count = 0), RegionEntry +Segment at 14:25 (count = 0), Skipped +Segment at 14:29 (count = 0), RegionEntry +Segment at 14:42 (count = 0), Skipped +Segment at 14:46 (count = 0), RegionEntry +Segment at 14:60 (count = 0), Skipped +Segment at 14:61 (count = 0), RegionEntry +Segment at 16:10 (count = 0), RegionEntry +Segment at 16:11 (count = 0), Skipped +Segment at 17:9 (count = 0), RegionEntry +Segment at 18:18 (count = 0), Skipped +Segment at 20:9 (count = 0), RegionEntry +Segment at 20:15 (count = 0), Skipped +Segment at 23:9 (count = 1), RegionEntry +Segment at 24:12 (count = 0), Skipped +Segment at 24:13 (count = 1), RegionEntry +Segment at 26:6 (count = 0), Skipped +Segment at 28:8 (count = 1), RegionEntry +Segment at 28:21 (count = 0), Skipped +Segment at 28:22 (count = 1), RegionEntry +Segment at 30:6 (count = 0), Skipped +Segment at 30:15 (count = 0), RegionEntry +Segment at 30:28 (count = 0), Skipped +Segment at 31:12 (count = 0), RegionEntry +Segment at 31:25 (count = 0), Skipped +Segment at 31:29 (count = 0), RegionEntry +Segment at 31:42 (count = 0), Skipped +Segment at 31:46 (count = 0), RegionEntry +Segment at 31:60 (count = 0), Skipped +Segment at 31:61 (count = 0), RegionEntry +Segment at 33:10 (count = 0), RegionEntry +Segment at 33:11 (count = 0), Skipped +Segment at 34:9 (count = 0), RegionEntry +Segment at 34:23 (count = 0), Skipped +Segment at 36:9 (count = 0), RegionEntry +Segment at 36:15 (count = 0), Skipped +Segment at 39:8 (count = 1), RegionEntry +Segment at 39:12 (count = 0), Skipped +Segment at 40:13 (count = 1), RegionEntry +Segment at 41:16 (count = 0), Skipped +Segment at 41:17 (count = 1), RegionEntry +Segment at 43:10 (count = 0), Skipped +Segment at 45:12 (count = 1), RegionEntry +Segment at 45:25 (count = 0), Skipped +Segment at 45:26 (count = 1), RegionEntry +Segment at 47:10 (count = 0), Skipped +Segment at 48:17 (count = 0), RegionEntry +Segment at 48:30 (count = 0), Skipped +Segment at 49:16 (count = 0), RegionEntry +Segment at 49:29 (count = 0), Skipped +Segment at 49:33 (count = 0), RegionEntry +Segment at 49:46 (count = 0), Skipped +Segment at 49:50 (count = 0), RegionEntry +Segment at 49:64 (count = 0), Skipped +Segment at 49:65 (count = 0), RegionEntry +Segment at 51:14 (count = 0), RegionEntry +Segment at 51:15 (count = 0), Skipped +Segment at 52:13 (count = 0), RegionEntry +Segment at 52:27 (count = 0), Skipped +Segment at 54:13 (count = 0), RegionEntry +Segment at 54:19 (count = 0), Skipped +Segment at 59:9 (count = 1), RegionEntry +Segment at 60:12 (count = 0), Skipped +Segment at 60:13 (count = 1), RegionEntry +Segment at 62:6 (count = 0), Skipped +Segment at 64:9 (count = 0), RegionEntry +Segment at 64:10 (count = 0), Skipped +Segment at 64:16 (count = 1), RegionEntry +Segment at 64:29 (count = 0), Skipped +Segment at 64:30 (count = 0), RegionEntry +Segment at 66:6 (count = 0), Skipped +Segment at 66:15 (count = 1), RegionEntry +Segment at 66:28 (count = 0), Skipped +Segment at 67:12 (count = 0), RegionEntry +Segment at 67:25 (count = 0), Skipped +Segment at 67:29 (count = 0), RegionEntry +Segment at 67:42 (count = 0), Skipped +Segment at 67:46 (count = 0), RegionEntry +Segment at 67:60 (count = 0), Skipped +Segment at 67:61 (count = 0), RegionEntry +Segment at 69:10 (count = 0), RegionEntry +Segment at 69:11 (count = 0), Skipped +Segment at 70:9 (count = 0), RegionEntry +Segment at 70:23 (count = 0), Skipped +Segment at 72:13 (count = 1), RegionEntry +Segment at 74:15 (count = 0), Skipped +Segment at 77:9 (count = 0), RegionEntry +Segment at 77:10 (count = 0), Skipped +Segment at 77:16 (count = 0), RegionEntry +Segment at 77:29 (count = 0), Skipped +Segment at 77:30 (count = 0), RegionEntry +Segment at 79:6 (count = 0), Skipped +Segment at 79:15 (count = 0), RegionEntry +Segment at 79:28 (count = 0), Skipped +Segment at 80:12 (count = 0), RegionEntry +Segment at 80:25 (count = 0), Skipped +Segment at 80:29 (count = 0), RegionEntry +Segment at 80:42 (count = 0), Skipped +Segment at 80:46 (count = 0), RegionEntry +Segment at 80:60 (count = 0), Skipped +Segment at 80:61 (count = 0), RegionEntry +Segment at 82:10 (count = 0), RegionEntry +Segment at 82:11 (count = 0), Skipped +Segment at 83:9 (count = 0), RegionEntry +Segment at 83:23 (count = 0), Skipped +Segment at 85:9 (count = 0), RegionEntry +Segment at 85:15 (count = 0), Skipped +Segment at 87:1 (count = 1), RegionEntry +Segment at 87:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.dead_code.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.dead_code.txt new file mode 100644 index 0000000000000..a2187d477c820 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.dead_code.txt @@ -0,0 +1,47 @@ +Counter in file 0 3:1 -> 10:15, 0 +Counter in file 0 10:16 -> 12:6, 0 +Counter in file 0 12:6 -> 12:7, 0 +Counter in file 0 13:1 -> 13:2, 0 +Counter in file 0 15:1 -> 22:15, 0 +Counter in file 0 22:16 -> 24:6, 0 +Counter in file 0 24:6 -> 24:7, 0 +Counter in file 0 25:1 -> 25:2, 0 +Counter in file 0 27:1 -> 34:15, #1 +Counter in file 0 34:16 -> 36:6, #2 +Counter in file 0 36:6 -> 36:7, (#1 - #2) +Counter in file 0 37:1 -> 37:2, (#2 + (#1 - #2)) +Emitting segments for file: ../coverage/dead_code.rs +Combined regions: + 3:1 -> 10:15 (count=0) + 10:16 -> 12:6 (count=0) + 12:6 -> 12:7 (count=0) + 13:1 -> 13:2 (count=0) + 15:1 -> 22:15 (count=0) + 22:16 -> 24:6 (count=0) + 24:6 -> 24:7 (count=0) + 25:1 -> 25:2 (count=0) + 27:1 -> 34:15 (count=1) + 34:16 -> 36:6 (count=1) + 36:6 -> 36:7 (count=0) + 37:1 -> 37:2 (count=1) +Segment at 3:1 (count = 0), RegionEntry +Segment at 10:15 (count = 0), Skipped +Segment at 10:16 (count = 0), RegionEntry +Segment at 12:6 (count = 0), RegionEntry +Segment at 12:7 (count = 0), Skipped +Segment at 13:1 (count = 0), RegionEntry +Segment at 13:2 (count = 0), Skipped +Segment at 15:1 (count = 0), RegionEntry +Segment at 22:15 (count = 0), Skipped +Segment at 22:16 (count = 0), RegionEntry +Segment at 24:6 (count = 0), RegionEntry +Segment at 24:7 (count = 0), Skipped +Segment at 25:1 (count = 0), RegionEntry +Segment at 25:2 (count = 0), Skipped +Segment at 27:1 (count = 1), RegionEntry +Segment at 34:15 (count = 0), Skipped +Segment at 34:16 (count = 1), RegionEntry +Segment at 36:6 (count = 0), RegionEntry +Segment at 36:7 (count = 0), Skipped +Segment at 37:1 (count = 1), RegionEntry +Segment at 37:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.drop_trait.txt similarity index 55% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.drop_trait.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.drop_trait.txt index 375025fe8bcc2..66c51e3a2982d 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.drop_trait.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.drop_trait.txt @@ -1,20 +1,16 @@ -Counter in file 0 9:24 -> 11:6, #1 -Counter in file 0 15:9 -> 17:42, #1 -Counter in file 0 19:8 -> 19:12, (#1 + 0) +Counter in file 0 9:5 -> 11:6, #1 +Counter in file 0 14:1 -> 19:12, #1 Counter in file 0 20:9 -> 21:22, #2 Counter in file 0 27:1 -> 27:2, (#2 + 0) Emitting segments for file: ../coverage/drop_trait.rs Combined regions: - 9:24 -> 11:6 (count=2) - 15:9 -> 17:42 (count=1) - 19:8 -> 19:12 (count=1) + 9:5 -> 11:6 (count=2) + 14:1 -> 19:12 (count=1) 20:9 -> 21:22 (count=1) 27:1 -> 27:2 (count=1) -Segment at 9:24 (count = 2), RegionEntry +Segment at 9:5 (count = 2), RegionEntry Segment at 11:6 (count = 0), Skipped -Segment at 15:9 (count = 1), RegionEntry -Segment at 17:42 (count = 0), Skipped -Segment at 19:8 (count = 1), RegionEntry +Segment at 14:1 (count = 1), RegionEntry Segment at 19:12 (count = 0), Skipped Segment at 20:9 (count = 1), RegionEntry Segment at 21:22 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt new file mode 100644 index 0000000000000..b41f482173b3d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt @@ -0,0 +1,44 @@ +Counter in file 0 17:5 -> 19:6, #1 +Counter in file 0 17:5 -> 19:6, #1 +Counter in file 0 22:1 -> 30:12, #1 +Counter in file 0 31:9 -> 32:22, #2 +Counter in file 0 42:1 -> 42:2, (#2 + 0) +Counter in file 0 10:5 -> 12:6, #1 +Counter in file 0 10:5 -> 12:6, #1 +Emitting segments for file: ../coverage/generics.rs +Combined regions: + 10:5 -> 12:6 (count=3) + 17:5 -> 19:6 (count=2) + 22:1 -> 30:12 (count=1) + 31:9 -> 32:22 (count=1) + 42:1 -> 42:2 (count=1) +Segment at 10:5 (count = 3), RegionEntry +Segment at 12:6 (count = 0), Skipped +Segment at 17:5 (count = 2), RegionEntry +Segment at 19:6 (count = 0), Skipped +Segment at 22:1 (count = 1), RegionEntry +Segment at 30:12 (count = 0), Skipped +Segment at 31:9 (count = 1), RegionEntry +Segment at 32:22 (count = 0), Skipped +Segment at 42:1 (count = 1), RegionEntry +Segment at 42:2 (count = 0), Skipped +Emitting segments for function: _RNvMCs4fqI2P2rA04_8genericsINtB2_8FireworkdE12set_strengthB2_ +Combined regions: + 10:5 -> 12:6 (count=2) +Segment at 10:5 (count = 2), RegionEntry +Segment at 12:6 (count = 0), Skipped +Emitting segments for function: _RNvMCs4fqI2P2rA04_8genericsINtB2_8FireworklE12set_strengthB2_ +Combined regions: + 10:5 -> 12:6 (count=1) +Segment at 10:5 (count = 1), RegionEntry +Segment at 12:6 (count = 0), Skipped +Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworklENtNtNtCs6HRHKMTmAen_4core3ops4drop4Drop4dropB4_ +Combined regions: + 17:5 -> 19:6 (count=1) +Segment at 17:5 (count = 1), RegionEntry +Segment at 19:6 (count = 0), Skipped +Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworkdENtNtNtCs6HRHKMTmAen_4core3ops4drop4Drop4dropB4_ +Combined regions: + 17:5 -> 19:6 (count=1) +Segment at 17:5 (count = 1), RegionEntry +Segment at 19:6 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.if.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if.txt similarity index 66% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.if.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if.txt index c2bef365ea9d8..2e802a462ea2c 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.if.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if.txt @@ -1,18 +1,14 @@ -Counter in file 0 8:5 -> 18:10, #1 -Counter in file 0 21:9 -> 21:16, (#1 + 0) +Counter in file 0 3:1 -> 21:16, #1 Counter in file 0 22:5 -> 27:6, #2 Counter in file 0 27:6 -> 27:7, (#1 - #2) Counter in file 0 28:1 -> 28:2, (#2 + (#1 - #2)) Emitting segments for file: ../coverage/if.rs Combined regions: - 8:5 -> 18:10 (count=1) - 21:9 -> 21:16 (count=1) + 3:1 -> 21:16 (count=1) 22:5 -> 27:6 (count=1) 27:6 -> 27:7 (count=0) 28:1 -> 28:2 (count=1) -Segment at 8:5 (count = 1), RegionEntry -Segment at 18:10 (count = 0), Skipped -Segment at 21:9 (count = 1), RegionEntry +Segment at 3:1 (count = 1), RegionEntry Segment at 21:16 (count = 0), Skipped Segment at 22:5 (count = 1), RegionEntry Segment at 27:6 (count = 0), RegionEntry diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.if_else.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if_else.txt similarity index 90% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.if_else.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if_else.txt index faf5c094bbaaa..03b35b0f00999 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.if_else.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if_else.txt @@ -1,4 +1,4 @@ -Counter in file 0 7:9 -> 11:16, #1 +Counter in file 0 3:1 -> 11:16, #1 Counter in file 0 12:5 -> 17:6, #2 Counter in file 0 20:9 -> 22:16, (#1 - #2) Counter in file 0 26:9 -> 26:16, (#2 + (#1 - #2)) @@ -7,14 +7,14 @@ Counter in file 0 34:5 -> 39:6, ((#2 + (#1 - #2)) - #3) Counter in file 0 40:1 -> 40:2, (#3 + ((#2 + (#1 - #2)) - #3)) Emitting segments for file: ../coverage/if_else.rs Combined regions: - 7:9 -> 11:16 (count=1) + 3:1 -> 11:16 (count=1) 12:5 -> 17:6 (count=1) 20:9 -> 22:16 (count=0) 26:9 -> 26:16 (count=1) 27:5 -> 32:6 (count=1) 34:5 -> 39:6 (count=0) 40:1 -> 40:2 (count=1) -Segment at 7:9 (count = 1), RegionEntry +Segment at 3:1 (count = 1), RegionEntry Segment at 11:16 (count = 0), Skipped Segment at 12:5 (count = 1), RegionEntry Segment at 17:6 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.inner_items.txt new file mode 100644 index 0000000000000..5dc704d6149f1 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.inner_items.txt @@ -0,0 +1,44 @@ +Counter in file 0 18:5 -> 22:6, #1 +Counter in file 0 3:1 -> 3:11, #1 +Counter in file 0 7:9 -> 10:15, (#1 + 0) +Counter in file 0 10:16 -> 12:6, #2 +Counter in file 0 12:6 -> 12:7, (#1 - #2) +Counter in file 0 48:8 -> 48:15, (#2 + (#1 - #2)) +Counter in file 0 48:16 -> 50:6, #3 +Counter in file 0 50:6 -> 50:7, ((#2 + (#1 - #2)) - #3) +Counter in file 0 52:9 -> 57:2, (#3 + ((#2 + (#1 - #2)) - #3)) +Counter in file 0 33:9 -> 36:10, #1 +Counter in file 0 40:9 -> 43:10, #1 +Emitting segments for file: ../coverage/inner_items.rs +Combined regions: + 3:1 -> 3:11 (count=1) + 7:9 -> 10:15 (count=1) + 10:16 -> 12:6 (count=1) + 12:6 -> 12:7 (count=0) + 18:5 -> 22:6 (count=3) + 33:9 -> 36:10 (count=1) + 40:9 -> 43:10 (count=1) + 48:8 -> 48:15 (count=1) + 48:16 -> 50:6 (count=1) + 50:6 -> 50:7 (count=0) + 52:9 -> 57:2 (count=1) +Segment at 3:1 (count = 1), RegionEntry +Segment at 3:11 (count = 0), Skipped +Segment at 7:9 (count = 1), RegionEntry +Segment at 10:15 (count = 0), Skipped +Segment at 10:16 (count = 1), RegionEntry +Segment at 12:6 (count = 0), RegionEntry +Segment at 12:7 (count = 0), Skipped +Segment at 18:5 (count = 3), RegionEntry +Segment at 22:6 (count = 0), Skipped +Segment at 33:9 (count = 1), RegionEntry +Segment at 36:10 (count = 0), Skipped +Segment at 40:9 (count = 1), RegionEntry +Segment at 43:10 (count = 0), Skipped +Segment at 48:8 (count = 1), RegionEntry +Segment at 48:15 (count = 0), Skipped +Segment at 48:16 (count = 1), RegionEntry +Segment at 50:6 (count = 0), RegionEntry +Segment at 50:7 (count = 0), Skipped +Segment at 52:9 (count = 1), RegionEntry +Segment at 57:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.lazy_boolean.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.lazy_boolean.txt similarity index 54% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.lazy_boolean.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.lazy_boolean.txt index 8e56d79d9d2aa..d5667fb861e2c 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.lazy_boolean.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.lazy_boolean.txt @@ -1,62 +1,48 @@ -Counter in file 0 7:9 -> 9:42, #1 -Counter in file 0 10:8 -> 10:15, (#1 + 0) +Counter in file 0 3:1 -> 10:15, #1 Counter in file 0 10:16 -> 14:6, #2 Counter in file 0 14:6 -> 14:7, (#1 - #2) Counter in file 0 16:9 -> 16:17, ((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) Counter in file 0 18:13 -> 18:18, (#2 + (#1 - #2)) Counter in file 0 20:13 -> 20:18, ((#2 + (#1 - #2)) - #3) -Counter in file 0 20:18 -> 20:19, (#3 + #4) -Counter in file 0 20:18 -> 20:19, (((#2 + (#1 - #2)) - #3) - #4) Counter in file 0 23:9 -> 23:17, ((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) Counter in file 0 25:13 -> 25:18, (((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) + 0) Counter in file 0 27:13 -> 27:18, (((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) -Counter in file 0 27:18 -> 27:19, (#5 + #6) -Counter in file 0 27:18 -> 27:19, ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6) -Counter in file 0 29:9 -> 29:17, ((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) +Counter in file 0 29:9 -> 29:17, (#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) Counter in file 0 29:20 -> 29:25, (((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) + 0) Counter in file 0 29:29 -> 29:34, #7 -Counter in file 0 29:34 -> 29:35, ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8) -Counter in file 0 29:34 -> 29:35, (#7 - #8) -Counter in file 0 30:9 -> 30:17, ((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) -Counter in file 0 30:20 -> 30:25, (((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) + 0) +Counter in file 0 30:9 -> 30:17, (#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) +Counter in file 0 30:20 -> 30:25, ((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) + 0) Counter in file 0 30:29 -> 30:34, #9 -Counter in file 0 30:34 -> 30:35, ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10) -Counter in file 0 30:34 -> 30:35, (#9 - #10) -Counter in file 0 33:9 -> 34:16, (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) + 0) +Counter in file 0 33:9 -> 34:16, ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) + 0) Counter in file 0 35:5 -> 38:6, #11 -Counter in file 0 38:6 -> 38:7, (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11) -Counter in file 0 41:9 -> 41:16, (#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) +Counter in file 0 38:6 -> 38:7, ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11) +Counter in file 0 41:9 -> 41:16, (#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) Counter in file 0 42:5 -> 45:6, #12 -Counter in file 0 47:5 -> 50:6, ((#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) - #12) -Counter in file 0 52:8 -> 52:16, (#12 + ((#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) - #12)) +Counter in file 0 47:5 -> 50:6, ((#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) - #12) +Counter in file 0 52:8 -> 52:16, (#12 + ((#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) - #12)) Counter in file 0 52:17 -> 54:6, #13 -Counter in file 0 54:6 -> 54:7, ((#12 + ((#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) - #12)) - #13) -Counter in file 0 56:8 -> 56:15, (#13 + ((#12 + ((#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) - #12)) - #13)) +Counter in file 0 54:6 -> 54:7, ((#12 + ((#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) - #12)) - #13) +Counter in file 0 56:8 -> 56:15, (#13 + ((#12 + ((#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) - #12)) - #13)) Counter in file 0 56:16 -> 58:6, #14 -Counter in file 0 58:12 -> 60:6, ((#13 + ((#12 + ((#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) - #12)) - #13)) - #14) -Counter in file 0 61:1 -> 61:2, (#14 + ((#13 + ((#12 + ((#11 + (((#9 - #10) + ((((#7 - #8) + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + #8)) - #9) + #10)) - #11)) - #12)) - #13)) - #14)) +Counter in file 0 58:12 -> 60:6, ((#13 + ((#12 + ((#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) - #12)) - #13)) - #14) +Counter in file 0 61:1 -> 61:2, (#14 + ((#13 + ((#12 + ((#11 + ((#10 + (((#8 + ((((#5 + #6) + ((((#3 + #4) + (((#2 + (#1 - #2)) - #3) - #4)) - #5) - #6)) - #7) + (#7 - #8))) - #9) + (#9 - #10))) - #11)) - #12)) - #13)) - #14)) Emitting segments for file: ../coverage/lazy_boolean.rs Combined regions: - 7:9 -> 9:42 (count=1) - 10:8 -> 10:15 (count=1) + 3:1 -> 10:15 (count=1) 10:16 -> 14:6 (count=1) 14:6 -> 14:7 (count=0) 16:9 -> 16:17 (count=1) 18:13 -> 18:18 (count=1) 20:13 -> 20:18 (count=0) - 20:18 -> 20:19 (count=1) 23:9 -> 23:17 (count=1) 25:13 -> 25:18 (count=1) 27:13 -> 27:18 (count=1) - 27:18 -> 27:19 (count=1) 29:9 -> 29:17 (count=1) 29:20 -> 29:25 (count=1) 29:29 -> 29:34 (count=1) - 29:34 -> 29:35 (count=1) 30:9 -> 30:17 (count=1) 30:20 -> 30:25 (count=1) 30:29 -> 30:34 (count=0) - 30:34 -> 30:35 (count=1) 33:9 -> 34:16 (count=1) 35:5 -> 38:6 (count=0) 38:6 -> 38:7 (count=1) @@ -70,9 +56,7 @@ Combined regions: 56:16 -> 58:6 (count=1) 58:12 -> 60:6 (count=0) 61:1 -> 61:2 (count=1) -Segment at 7:9 (count = 1), RegionEntry -Segment at 9:42 (count = 0), Skipped -Segment at 10:8 (count = 1), RegionEntry +Segment at 3:1 (count = 1), RegionEntry Segment at 10:15 (count = 0), Skipped Segment at 10:16 (count = 1), RegionEntry Segment at 14:6 (count = 0), RegionEntry @@ -82,29 +66,25 @@ Segment at 16:17 (count = 0), Skipped Segment at 18:13 (count = 1), RegionEntry Segment at 18:18 (count = 0), Skipped Segment at 20:13 (count = 0), RegionEntry -Segment at 20:18 (count = 1), RegionEntry -Segment at 20:19 (count = 0), Skipped +Segment at 20:18 (count = 0), Skipped Segment at 23:9 (count = 1), RegionEntry Segment at 23:17 (count = 0), Skipped Segment at 25:13 (count = 1), RegionEntry Segment at 25:18 (count = 0), Skipped Segment at 27:13 (count = 1), RegionEntry -Segment at 27:18 (count = 1), RegionEntry -Segment at 27:19 (count = 0), Skipped +Segment at 27:18 (count = 0), Skipped Segment at 29:9 (count = 1), RegionEntry Segment at 29:17 (count = 0), Skipped Segment at 29:20 (count = 1), RegionEntry Segment at 29:25 (count = 0), Skipped Segment at 29:29 (count = 1), RegionEntry -Segment at 29:34 (count = 1), RegionEntry -Segment at 29:35 (count = 0), Skipped +Segment at 29:34 (count = 0), Skipped Segment at 30:9 (count = 1), RegionEntry Segment at 30:17 (count = 0), Skipped Segment at 30:20 (count = 1), RegionEntry Segment at 30:25 (count = 0), Skipped Segment at 30:29 (count = 0), RegionEntry -Segment at 30:34 (count = 1), RegionEntry -Segment at 30:35 (count = 0), Skipped +Segment at 30:34 (count = 0), Skipped Segment at 33:9 (count = 1), RegionEntry Segment at 34:16 (count = 0), Skipped Segment at 35:5 (count = 0), RegionEntry diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.loop_break_value.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loop_break_value.txt similarity index 53% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.loop_break_value.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loop_break_value.txt index a6144b8072ace..17bd5c2ff3186 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.loop_break_value.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loop_break_value.txt @@ -1,6 +1,6 @@ -Counter in file 0 3:11 -> 13:2, #1 +Counter in file 0 3:1 -> 13:2, #1 Emitting segments for file: ../coverage/loop_break_value.rs Combined regions: - 3:11 -> 13:2 (count=1) -Segment at 3:11 (count = 1), RegionEntry + 3:1 -> 13:2 (count=1) +Segment at 3:1 (count = 1), RegionEntry Segment at 13:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loops_branches.txt similarity index 70% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.loops_branches.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loops_branches.txt index d8af6998964cf..d1da50b1529e4 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.loops_branches.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loops_branches.txt @@ -1,24 +1,22 @@ -Counter in file 0 10:12 -> 10:16, #1 +Counter in file 0 9:5 -> 10:16, #1 Counter in file 0 11:16 -> 11:21, #2 Counter in file 0 14:14 -> 14:15, (#2 - #5) -Counter in file 0 15:13 -> 15:31, (0 + (#2 - #5)) +Counter in file 0 15:13 -> 15:31, ((0 - #6) + (#2 - #5)) Counter in file 0 15:31 -> 15:32, #4 -Counter in file 0 17:10 -> 17:11, #3 Counter in file 0 18:9 -> 18:15, (#3 + 0) Counter in file 0 19:5 -> 19:6, (#4 + (#3 + 0)) -Counter in file 0 22:11 -> 25:2, #1 +Counter in file 0 22:1 -> 25:2, #1 Emitting segments for file: ../coverage/loops_branches.rs Combined regions: - 10:12 -> 10:16 (count=1) + 9:5 -> 10:16 (count=1) 11:16 -> 11:21 (count=1) 14:14 -> 14:15 (count=1) 15:13 -> 15:31 (count=1) 15:31 -> 15:32 (count=0) - 17:10 -> 17:11 (count=1) 18:9 -> 18:15 (count=1) 19:5 -> 19:6 (count=1) - 22:11 -> 25:2 (count=1) -Segment at 10:12 (count = 1), RegionEntry + 22:1 -> 25:2 (count=1) +Segment at 9:5 (count = 1), RegionEntry Segment at 10:16 (count = 0), Skipped Segment at 11:16 (count = 1), RegionEntry Segment at 11:21 (count = 0), Skipped @@ -27,11 +25,9 @@ Segment at 14:15 (count = 0), Skipped Segment at 15:13 (count = 1), RegionEntry Segment at 15:31 (count = 0), RegionEntry Segment at 15:32 (count = 0), Skipped -Segment at 17:10 (count = 1), RegionEntry -Segment at 17:11 (count = 0), Skipped Segment at 18:9 (count = 1), RegionEntry Segment at 18:15 (count = 0), Skipped Segment at 19:5 (count = 1), RegionEntry Segment at 19:6 (count = 0), Skipped -Segment at 22:11 (count = 1), RegionEntry +Segment at 22:1 (count = 1), RegionEntry Segment at 25:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.nested_loops.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.nested_loops.txt new file mode 100644 index 0000000000000..f30dd9e37164e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.nested_loops.txt @@ -0,0 +1,58 @@ +Counter in file 0 1:1 -> 3:27, #1 +Counter in file 0 5:19 -> 5:32, (#1 + (#2 + #3)) +Counter in file 0 6:13 -> 7:24, ((#1 + (#2 + #3)) - #4) +Counter in file 0 8:13 -> 8:14, ((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) +Counter in file 0 8:18 -> 8:23, (((#1 + (#2 + #3)) - #4) + (#6 + #7)) +Counter in file 0 9:16 -> 9:22, (((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) + 0) +Counter in file 0 10:17 -> 10:22, #2 +Counter in file 0 11:14 -> 14:22, (((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) - #2) +Counter in file 0 15:17 -> 16:27, ((((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) - #2) - #7) +Counter in file 0 17:21 -> 17:33, #5 +Counter in file 0 18:24 -> 20:18, #6 +Counter in file 0 21:14 -> 21:15, #7 +Counter in file 0 23:9 -> 23:23, (#2 + #3) +Counter in file 0 25:1 -> 25:2, (#5 + #4) +Emitting segments for file: ../coverage/nested_loops.rs +Combined regions: + 1:1 -> 3:27 (count=1) + 5:19 -> 5:32 (count=1) + 6:13 -> 7:24 (count=1) + 8:13 -> 8:14 (count=3) + 8:18 -> 8:23 (count=3) + 9:16 -> 9:22 (count=3) + 10:17 -> 10:22 (count=0) + 11:14 -> 14:22 (count=3) + 15:17 -> 16:27 (count=1) + 17:21 -> 17:33 (count=1) + 18:24 -> 20:18 (count=0) + 21:14 -> 21:15 (count=2) + 23:9 -> 23:23 (count=0) + 25:1 -> 25:2 (count=1) +Segment at 1:1 (count = 1), RegionEntry +Segment at 3:27 (count = 0), Skipped +Segment at 5:19 (count = 1), RegionEntry +Segment at 5:32 (count = 0), Skipped +Segment at 6:13 (count = 1), RegionEntry +Segment at 7:24 (count = 0), Skipped +Segment at 8:13 (count = 3), RegionEntry +Segment at 8:14 (count = 0), Skipped +Segment at 8:18 (count = 3), RegionEntry +Segment at 8:23 (count = 0), Skipped +Segment at 9:16 (count = 3), RegionEntry +Segment at 9:22 (count = 0), Skipped +Segment at 10:17 (count = 0), RegionEntry +Segment at 10:22 (count = 0), Skipped +Segment at 11:14 (count = 3), RegionEntry +Segment at 14:22 (count = 0), Skipped +Segment at 15:17 (count = 1), RegionEntry +Segment at 16:27 (count = 0), Skipped +Segment at 17:21 (count = 1), RegionEntry +Segment at 17:33 (count = 0), Skipped +Segment at 18:24 (count = 0), RegionEntry +Segment at 20:18 (count = 0), Skipped +Segment at 21:14 (count = 2), RegionEntry +Segment at 21:15 (count = 0), Skipped +Segment at 23:9 (count = 0), RegionEntry +Segment at 23:23 (count = 0), Skipped +Segment at 25:1 (count = 1), RegionEntry +Segment at 25:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt new file mode 100644 index 0000000000000..fbc3adbfb6d70 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt @@ -0,0 +1,52 @@ +Counter in file 0 15:1 -> 16:27, #1 +Counter in file 0 17:11 -> 17:24, (#1 + (#2 + (#3 + #4))) +Counter in file 0 18:12 -> 18:26, ((#1 + (#2 + (#3 + #4))) - #5) +Counter in file 0 18:27 -> 21:10, #2 +Counter in file 0 21:19 -> 21:32, (((#1 + (#2 + (#3 + #4))) - #5) - #2) +Counter in file 0 21:33 -> 24:10, #3 +Counter in file 0 24:10 -> 24:11, #4 +Counter in file 0 25:9 -> 25:23, (#2 + (#3 + #4)) +Counter in file 0 27:5 -> 28:2, #5 +Counter in file 0 4:1 -> 5:18, #1 +Counter in file 0 5:19 -> 7:6, #2 +Counter in file 0 7:6 -> 7:7, (#1 - #2) +Counter in file 0 8:9 -> 13:2, (#2 + (#1 - #2)) +Emitting segments for file: ../coverage/overflow.rs +Combined regions: + 4:1 -> 5:18 (count=4) + 5:19 -> 7:6 (count=1) + 7:6 -> 7:7 (count=3) + 8:9 -> 13:2 (count=4) + 15:1 -> 16:27 (count=1) + 17:11 -> 17:24 (count=10) + 18:12 -> 18:26 (count=10) + 18:27 -> 21:10 (count=0) + 21:19 -> 21:32 (count=10) + 21:33 -> 24:10 (count=3) + 24:10 -> 24:11 (count=6) + 25:9 -> 25:23 (count=9) + 27:5 -> 28:2 (count=0) +Segment at 4:1 (count = 4), RegionEntry +Segment at 5:18 (count = 0), Skipped +Segment at 5:19 (count = 1), RegionEntry +Segment at 7:6 (count = 3), RegionEntry +Segment at 7:7 (count = 0), Skipped +Segment at 8:9 (count = 4), RegionEntry +Segment at 13:2 (count = 0), Skipped +Segment at 15:1 (count = 1), RegionEntry +Segment at 16:27 (count = 0), Skipped +Segment at 17:11 (count = 10), RegionEntry +Segment at 17:24 (count = 0), Skipped +Segment at 18:12 (count = 10), RegionEntry +Segment at 18:26 (count = 0), Skipped +Segment at 18:27 (count = 0), RegionEntry +Segment at 21:10 (count = 0), Skipped +Segment at 21:19 (count = 10), RegionEntry +Segment at 21:32 (count = 0), Skipped +Segment at 21:33 (count = 3), RegionEntry +Segment at 24:10 (count = 6), RegionEntry +Segment at 24:11 (count = 0), Skipped +Segment at 25:9 (count = 9), RegionEntry +Segment at 25:23 (count = 0), Skipped +Segment at 27:5 (count = 0), RegionEntry +Segment at 28:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt new file mode 100644 index 0000000000000..ad87f03026d38 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt @@ -0,0 +1,53 @@ +Counter in file 0 13:1 -> 14:27, #1 +Counter in file 0 15:11 -> 15:24, (#1 + (#2 + (#3 + #4))) +Counter in file 0 16:12 -> 16:26, ((#1 + (#2 + (#3 + #4))) - #5) +Counter in file 0 16:27 -> 18:10, #2 +Counter in file 0 18:19 -> 18:32, (((#1 + (#2 + (#3 + #4))) - #5) - #2) +Counter in file 0 18:33 -> 20:10, #3 +Counter in file 0 20:10 -> 20:11, #4 +Counter in file 0 21:9 -> 21:23, (#2 + (#3 + #4)) +Counter in file 0 23:5 -> 24:2, #5 +Counter in file 0 4:1 -> 4:36, #1 +Counter in file 0 5:8 -> 5:20, (#1 + 0) +Counter in file 0 6:9 -> 7:26, #2 +Counter in file 0 8:12 -> 11:2, (#1 - #2) +Emitting segments for file: ../coverage/panic_unwind.rs +Combined regions: + 4:1 -> 4:36 (count=4) + 5:8 -> 5:20 (count=4) + 6:9 -> 7:26 (count=1) + 8:12 -> 11:2 (count=3) + 13:1 -> 14:27 (count=1) + 15:11 -> 15:24 (count=10) + 16:12 -> 16:26 (count=10) + 16:27 -> 18:10 (count=0) + 18:19 -> 18:32 (count=10) + 18:33 -> 20:10 (count=3) + 20:10 -> 20:11 (count=6) + 21:9 -> 21:23 (count=9) + 23:5 -> 24:2 (count=0) +Segment at 4:1 (count = 4), RegionEntry +Segment at 4:36 (count = 0), Skipped +Segment at 5:8 (count = 4), RegionEntry +Segment at 5:20 (count = 0), Skipped +Segment at 6:9 (count = 1), RegionEntry +Segment at 7:26 (count = 0), Skipped +Segment at 8:12 (count = 3), RegionEntry +Segment at 11:2 (count = 0), Skipped +Segment at 13:1 (count = 1), RegionEntry +Segment at 14:27 (count = 0), Skipped +Segment at 15:11 (count = 10), RegionEntry +Segment at 15:24 (count = 0), Skipped +Segment at 16:12 (count = 10), RegionEntry +Segment at 16:26 (count = 0), Skipped +Segment at 16:27 (count = 0), RegionEntry +Segment at 18:10 (count = 0), Skipped +Segment at 18:19 (count = 10), RegionEntry +Segment at 18:32 (count = 0), Skipped +Segment at 18:33 (count = 3), RegionEntry +Segment at 20:10 (count = 6), RegionEntry +Segment at 20:11 (count = 0), Skipped +Segment at 21:9 (count = 9), RegionEntry +Segment at 21:23 (count = 0), Skipped +Segment at 23:5 (count = 0), RegionEntry +Segment at 24:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.partial_eq.txt new file mode 100644 index 0000000000000..fa5c12bb6f8e0 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.partial_eq.txt @@ -0,0 +1,66 @@ +Counter in file 0 4:10 -> 4:15, 0 +Counter in file 0 4:24 -> 4:25, 0 +Counter in file 0 4:24 -> 4:25, 0 +Counter in file 0 4:32 -> 4:33, 0 +Counter in file 0 4:32 -> 4:33, 0 +Counter in file 0 4:35 -> 4:36, 0 +Counter in file 0 4:39 -> 4:40, 0 +Counter in file 0 4:39 -> 4:40, 0 +Counter in file 0 4:39 -> 4:40, 0 +Counter in file 0 4:39 -> 4:40, 0 +Counter in file 0 4:48 -> 4:49, 0 +Counter in file 0 4:51 -> 4:52, 0 +Counter in file 0 4:53 -> 4:54, 0 +Counter in file 0 7:5 -> 7:6, #1 +Counter in file 0 7:5 -> 7:6, 0 +Counter in file 0 7:5 -> 7:6, 0 +Counter in file 0 7:5 -> 7:6, 0 +Counter in file 0 8:5 -> 8:17, 0 +Counter in file 0 8:5 -> 8:17, 0 +Counter in file 0 8:5 -> 8:17, 0 +Counter in file 0 21:1 -> 26:2, #1 +Counter in file 0 4:17 -> 4:22, #1 +Counter in file 0 12:5 -> 18:6, #1 +Counter in file 0 4:39 -> 4:40, #1 +Counter in file 0 8:5 -> 8:17, #1 +Emitting segments for file: ../coverage/partial_eq.rs +Combined regions: + 4:10 -> 4:15 (count=0) + 4:17 -> 4:22 (count=2) + 4:24 -> 4:25 (count=0) + 4:32 -> 4:33 (count=0) + 4:35 -> 4:36 (count=0) + 4:39 -> 4:40 (count=1) + 4:48 -> 4:49 (count=0) + 4:51 -> 4:52 (count=0) + 4:53 -> 4:54 (count=0) + 7:5 -> 7:6 (count=1) + 8:5 -> 8:17 (count=0) + 12:5 -> 18:6 (count=2) + 21:1 -> 26:2 (count=1) +Segment at 4:10 (count = 0), RegionEntry +Segment at 4:15 (count = 0), Skipped +Segment at 4:17 (count = 2), RegionEntry +Segment at 4:22 (count = 0), Skipped +Segment at 4:24 (count = 0), RegionEntry +Segment at 4:25 (count = 0), Skipped +Segment at 4:32 (count = 0), RegionEntry +Segment at 4:33 (count = 0), Skipped +Segment at 4:35 (count = 0), RegionEntry +Segment at 4:36 (count = 0), Skipped +Segment at 4:39 (count = 1), RegionEntry +Segment at 4:40 (count = 0), Skipped +Segment at 4:48 (count = 0), RegionEntry +Segment at 4:49 (count = 0), Skipped +Segment at 4:51 (count = 0), RegionEntry +Segment at 4:52 (count = 0), Skipped +Segment at 4:53 (count = 0), RegionEntry +Segment at 4:54 (count = 0), Skipped +Segment at 7:5 (count = 1), RegionEntry +Segment at 7:6 (count = 0), Skipped +Segment at 8:5 (count = 0), RegionEntry +Segment at 8:17 (count = 0), Skipped +Segment at 12:5 (count = 2), RegionEntry +Segment at 18:6 (count = 0), Skipped +Segment at 21:1 (count = 1), RegionEntry +Segment at 26:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_loop.txt similarity index 57% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_loop.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_loop.txt index 255173e5534d1..c0b09486dfba4 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_loop.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_loop.txt @@ -1,26 +1,20 @@ -Counter in file 0 7:9 -> 9:26, #1 -Counter in file 0 12:9 -> 12:16, (#1 + 0) +Counter in file 0 3:1 -> 12:16, #1 Counter in file 0 13:5 -> 18:6, #2 Counter in file 0 18:6 -> 18:7, (#1 - #2) Counter in file 0 23:13 -> 25:14, ((#2 + (#1 - #2)) + #3) -Counter in file 0 27:13 -> 27:18, #4 -Counter in file 0 30:9 -> 32:10, #3 -Counter in file 0 34:6 -> 34:7, (#2 + (#1 - #2)) -Counter in file 0 35:1 -> 35:2, (#4 + 0) +Counter in file 0 27:13 -> 27:18, (((#2 + (#1 - #2)) + #3) - #3) +Counter in file 0 29:10 -> 32:10, #3 +Counter in file 0 35:1 -> 35:2, ((((#2 + (#1 - #2)) + #3) - #3) + 0) Emitting segments for file: ../coverage/simple_loop.rs Combined regions: - 7:9 -> 9:26 (count=1) - 12:9 -> 12:16 (count=1) + 3:1 -> 12:16 (count=1) 13:5 -> 18:6 (count=1) 18:6 -> 18:7 (count=0) 23:13 -> 25:14 (count=11) 27:13 -> 27:18 (count=1) - 30:9 -> 32:10 (count=10) - 34:6 -> 34:7 (count=1) + 29:10 -> 32:10 (count=10) 35:1 -> 35:2 (count=1) -Segment at 7:9 (count = 1), RegionEntry -Segment at 9:26 (count = 0), Skipped -Segment at 12:9 (count = 1), RegionEntry +Segment at 3:1 (count = 1), RegionEntry Segment at 12:16 (count = 0), Skipped Segment at 13:5 (count = 1), RegionEntry Segment at 18:6 (count = 0), RegionEntry @@ -29,9 +23,7 @@ Segment at 23:13 (count = 11), RegionEntry Segment at 25:14 (count = 0), Skipped Segment at 27:13 (count = 1), RegionEntry Segment at 27:18 (count = 0), Skipped -Segment at 30:9 (count = 10), RegionEntry +Segment at 29:10 (count = 10), RegionEntry Segment at 32:10 (count = 0), Skipped -Segment at 34:6 (count = 1), RegionEntry -Segment at 34:7 (count = 0), Skipped Segment at 35:1 (count = 1), RegionEntry Segment at 35:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_match.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_match.txt similarity index 72% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_match.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_match.txt index 1682a379bc0ff..c01630bd87bc9 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_match.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_match.txt @@ -1,5 +1,4 @@ -Counter in file 0 7:9 -> 9:26, #1 -Counter in file 0 10:8 -> 10:15, (#1 + 0) +Counter in file 0 3:1 -> 10:15, #1 Counter in file 0 10:16 -> 12:6, #2 Counter in file 0 12:6 -> 12:7, (#1 - #2) Counter in file 0 15:9 -> 15:10, (((#2 + (#1 - #2)) + (#3 + #4)) - #5) @@ -7,16 +6,12 @@ Counter in file 0 17:9 -> 17:13, ((#2 + (#1 - #2)) + (#3 + #4)) Counter in file 0 22:13 -> 22:22, ((((#2 + (#1 - #2)) + (#3 + #4)) - #5) + 0) Counter in file 0 24:13 -> 24:14, #3 Counter in file 0 26:17 -> 28:18, ((((#2 + (#1 - #2)) + (#3 + #4)) - #5) + 0) -Counter in file 0 28:18 -> 28:19, ((((#2 + (#1 - #2)) + (#3 + #4)) - #5) - #3) Counter in file 0 30:13 -> 37:14, (#3 + 0) Counter in file 0 40:13 -> 40:15, #4 -Counter in file 0 42:6 -> 42:7, (#2 + (#1 - #2)) -Counter in file 0 42:6 -> 42:7, (#3 + #4) Counter in file 0 43:1 -> 43:2, #5 Emitting segments for file: ../coverage/simple_match.rs Combined regions: - 7:9 -> 9:26 (count=1) - 10:8 -> 10:15 (count=1) + 3:1 -> 10:15 (count=1) 10:16 -> 12:6 (count=1) 12:6 -> 12:7 (count=0) 15:9 -> 15:10 (count=2) @@ -24,14 +19,10 @@ Combined regions: 22:13 -> 22:22 (count=2) 24:13 -> 24:14 (count=1) 26:17 -> 28:18 (count=2) - 28:18 -> 28:19 (count=1) 30:13 -> 37:14 (count=1) 40:13 -> 40:15 (count=1) - 42:6 -> 42:7 (count=3) 43:1 -> 43:2 (count=1) -Segment at 7:9 (count = 1), RegionEntry -Segment at 9:26 (count = 0), Skipped -Segment at 10:8 (count = 1), RegionEntry +Segment at 3:1 (count = 1), RegionEntry Segment at 10:15 (count = 0), Skipped Segment at 10:16 (count = 1), RegionEntry Segment at 12:6 (count = 0), RegionEntry @@ -45,13 +36,10 @@ Segment at 22:22 (count = 0), Skipped Segment at 24:13 (count = 1), RegionEntry Segment at 24:14 (count = 0), Skipped Segment at 26:17 (count = 2), RegionEntry -Segment at 28:18 (count = 1), RegionEntry -Segment at 28:19 (count = 0), Skipped +Segment at 28:18 (count = 0), Skipped Segment at 30:13 (count = 1), RegionEntry Segment at 37:14 (count = 0), Skipped Segment at 40:13 (count = 1), RegionEntry Segment at 40:15 (count = 0), Skipped -Segment at 42:6 (count = 3), RegionEntry -Segment at 42:7 (count = 0), Skipped Segment at 43:1 (count = 1), RegionEntry Segment at 43:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.tight_inf_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.tight_inf_loop.txt new file mode 100644 index 0000000000000..a6cd429880856 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.tight_inf_loop.txt @@ -0,0 +1,10 @@ +Counter in file 0 1:1 -> 2:13, #1 +Counter in file 0 4:6 -> 5:2, (#1 - #2) +Emitting segments for file: ../coverage/tight_inf_loop.rs +Combined regions: + 1:1 -> 2:13 (count=1) + 4:6 -> 5:2 (count=1) +Segment at 1:1 (count = 1), RegionEntry +Segment at 2:13 (count = 0), Skipped +Segment at 4:6 (count = 1), RegionEntry +Segment at 5:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.try_error_result.txt similarity index 73% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.try_error_result.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.try_error_result.txt index a317cd792910d..2b7962df2f9f9 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.try_error_result.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.try_error_result.txt @@ -1,29 +1,26 @@ -Counter in file 0 13:9 -> 14:23, #1 +Counter in file 0 12:1 -> 14:23, #1 Counter in file 0 17:9 -> 17:10, ((#1 + (#2 + #3)) - #4) Counter in file 0 19:9 -> 19:14, (#1 + (#2 + #3)) -Counter in file 0 21:9 -> 25:26, #8 -Counter in file 0 27:13 -> 27:41, #9 +Counter in file 0 21:9 -> 25:26, (((#1 + (#2 + #3)) - #4) + 0) +Counter in file 0 27:13 -> 27:41, #8 Counter in file 0 27:41 -> 27:42, #5 -Counter in file 0 28:13 -> 28:42, (#9 - #5) +Counter in file 0 28:13 -> 28:42, (#8 - #5) Counter in file 0 28:42 -> 28:43, #6 -Counter in file 0 32:13 -> 32:42, (#8 - #9) +Counter in file 0 32:13 -> 32:42, (((#1 + (#2 + #3)) - #4) - #8) Counter in file 0 32:42 -> 32:43, #7 -Counter in file 0 33:10 -> 33:11, #2 -Counter in file 0 33:10 -> 33:11, #3 -Counter in file 0 34:6 -> 34:7, (#2 + #3) Counter in file 0 35:5 -> 35:11, #4 Counter in file 0 36:1 -> 36:2, ((#5 + (#6 + #7)) + #4) -Counter in file 0 5:8 -> 5:20, #1 +Counter in file 0 4:1 -> 5:20, #1 Counter in file 0 6:9 -> 6:16, #2 Counter in file 0 8:9 -> 8:15, (#1 - #2) Counter in file 0 10:1 -> 10:2, (#2 + (#1 - #2)) Emitting segments for file: ../coverage/try_error_result.rs Combined regions: - 5:8 -> 5:20 (count=6) + 4:1 -> 5:20 (count=6) 6:9 -> 6:16 (count=1) 8:9 -> 8:15 (count=5) 10:1 -> 10:2 (count=6) - 13:9 -> 14:23 (count=1) + 12:1 -> 14:23 (count=1) 17:9 -> 17:10 (count=6) 19:9 -> 19:14 (count=6) 21:9 -> 25:26 (count=6) @@ -33,11 +30,9 @@ Combined regions: 28:42 -> 28:43 (count=0) 32:13 -> 32:42 (count=5) 32:42 -> 32:43 (count=0) - 33:10 -> 33:11 (count=5) - 34:6 -> 34:7 (count=5) 35:5 -> 35:11 (count=0) 36:1 -> 36:2 (count=1) -Segment at 5:8 (count = 6), RegionEntry +Segment at 4:1 (count = 6), RegionEntry Segment at 5:20 (count = 0), Skipped Segment at 6:9 (count = 1), RegionEntry Segment at 6:16 (count = 0), Skipped @@ -45,7 +40,7 @@ Segment at 8:9 (count = 5), RegionEntry Segment at 8:15 (count = 0), Skipped Segment at 10:1 (count = 6), RegionEntry Segment at 10:2 (count = 0), Skipped -Segment at 13:9 (count = 1), RegionEntry +Segment at 12:1 (count = 1), RegionEntry Segment at 14:23 (count = 0), Skipped Segment at 17:9 (count = 6), RegionEntry Segment at 17:10 (count = 0), Skipped @@ -62,10 +57,6 @@ Segment at 28:43 (count = 0), Skipped Segment at 32:13 (count = 5), RegionEntry Segment at 32:42 (count = 0), RegionEntry Segment at 32:43 (count = 0), Skipped -Segment at 33:10 (count = 5), RegionEntry -Segment at 33:11 (count = 0), Skipped -Segment at 34:6 (count = 5), RegionEntry -Segment at 34:7 (count = 0), Skipped Segment at 35:5 (count = 0), RegionEntry Segment at 35:11 (count = 0), Skipped Segment at 36:1 (count = 1), RegionEntry diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt new file mode 100644 index 0000000000000..42cc4904e5f66 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt @@ -0,0 +1,110 @@ +Counter in file 0 25:1 -> 27:2, #1 +Counter in file 0 17:1 -> 19:2, #1 +Counter in file 0 17:1 -> 19:2, #1 +Counter in file 0 5:1 -> 12:2, #1 +Counter in file 0 17:1 -> 19:2, 0 +Counter in file 0 33:1 -> 35:2, 0 +Counter in file 0 45:1 -> 48:16, 0 +Counter in file 0 48:17 -> 50:6, 0 +Counter in file 0 50:6 -> 50:7, 0 +Counter in file 0 51:1 -> 51:2, 0 +Counter in file 0 53:1 -> 61:2, #1 +Counter in file 0 25:1 -> 27:2, #1 +Counter in file 0 29:1 -> 31:2, #1 +Counter in file 0 21:1 -> 23:2, #1 +Counter in file 0 5:1 -> 5:24, #1 +Counter in file 0 9:9 -> 11:15, (#1 + 0) +Counter in file 0 11:16 -> 13:6, #2 +Counter in file 0 13:6 -> 13:7, (#1 - #2) +Counter in file 0 14:5 -> 15:2, (#2 + (#1 - #2)) +Counter in file 0 21:1 -> 23:2, #1 +Counter in file 0 37:1 -> 40:16, #1 +Counter in file 0 40:17 -> 42:6, #2 +Counter in file 0 42:6 -> 42:7, (#1 - #2) +Counter in file 0 43:1 -> 43:2, (#2 + (#1 - #2)) +Emitting segments for file: ../coverage/lib/used_crate.rs +Combined regions: + 5:1 -> 5:24 (count=1) + 9:9 -> 11:15 (count=1) + 11:16 -> 13:6 (count=1) + 13:6 -> 13:7 (count=0) + 14:5 -> 15:2 (count=1) + 17:1 -> 19:2 (count=2) + 21:1 -> 23:2 (count=2) + 25:1 -> 27:2 (count=2) + 29:1 -> 31:2 (count=2) + 33:1 -> 35:2 (count=0) + 37:1 -> 40:16 (count=0) + 40:17 -> 42:6 (count=0) + 42:6 -> 42:7 (count=0) + 43:1 -> 43:2 (count=0) + 45:1 -> 48:16 (count=0) + 48:17 -> 50:6 (count=0) + 50:6 -> 50:7 (count=0) + 51:1 -> 51:2 (count=0) + 53:1 -> 61:2 (count=1) +Segment at 5:1 (count = 1), RegionEntry +Segment at 5:24 (count = 0), Skipped +Segment at 9:9 (count = 1), RegionEntry +Segment at 11:15 (count = 0), Skipped +Segment at 11:16 (count = 1), RegionEntry +Segment at 13:6 (count = 0), RegionEntry +Segment at 13:7 (count = 0), Skipped +Segment at 14:5 (count = 1), RegionEntry +Segment at 15:2 (count = 0), Skipped +Segment at 17:1 (count = 2), RegionEntry +Segment at 19:2 (count = 0), Skipped +Segment at 21:1 (count = 2), RegionEntry +Segment at 23:2 (count = 0), Skipped +Segment at 25:1 (count = 2), RegionEntry +Segment at 27:2 (count = 0), Skipped +Segment at 29:1 (count = 2), RegionEntry +Segment at 31:2 (count = 0), Skipped +Segment at 33:1 (count = 0), RegionEntry +Segment at 35:2 (count = 0), Skipped +Segment at 37:1 (count = 0), RegionEntry +Segment at 40:16 (count = 0), Skipped +Segment at 40:17 (count = 0), RegionEntry +Segment at 42:6 (count = 0), RegionEntry +Segment at 42:7 (count = 0), Skipped +Segment at 43:1 (count = 0), RegionEntry +Segment at 43:2 (count = 0), Skipped +Segment at 45:1 (count = 0), RegionEntry +Segment at 48:16 (count = 0), Skipped +Segment at 48:17 (count = 0), RegionEntry +Segment at 50:6 (count = 0), RegionEntry +Segment at 50:7 (count = 0), Skipped +Segment at 51:1 (count = 0), RegionEntry +Segment at 51:2 (count = 0), Skipped +Segment at 53:1 (count = 1), RegionEntry +Segment at 61:2 (count = 0), Skipped +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionRINtNtCsFAjihUSTht_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate +Combined regions: + 17:1 -> 19:2 (count=1) +Segment at 17:1 (count = 1), RegionEntry +Segment at 19:2 (count = 0), Skipped +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionReECs4fqI2P2rA04_10uses_crate +Combined regions: + 17:1 -> 19:2 (count=1) +Segment at 17:1 (count = 1), RegionEntry +Segment at 19:2 (count = 0), Skipped +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate46used_only_from_this_lib_crate_generic_functionINtNtCsFAjihUSTht_5alloc3vec3VeclEEB2_ +Combined regions: + 21:1 -> 23:2 (count=1) +Segment at 21:1 (count = 1), RegionEntry +Segment at 23:2 (count = 0), Skipped +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate46used_only_from_this_lib_crate_generic_functionReEB2_ +Combined regions: + 21:1 -> 23:2 (count=1) +Segment at 21:1 (count = 1), RegionEntry +Segment at 23:2 (count = 0), Skipped +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate50used_from_bin_crate_and_lib_crate_generic_functionINtNtCsFAjihUSTht_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate +Combined regions: + 25:1 -> 27:2 (count=1) +Segment at 25:1 (count = 1), RegionEntry +Segment at 27:2 (count = 0), Skipped +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate50used_from_bin_crate_and_lib_crate_generic_functionReEB2_ +Combined regions: + 25:1 -> 27:2 (count=1) +Segment at 25:1 (count = 1), RegionEntry +Segment at 27:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.while.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while.txt similarity index 84% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.while.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while.txt index b0e881da7c8cb..90629ac84cdf6 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.while.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while.txt @@ -1,14 +1,14 @@ -Counter in file 0 2:9 -> 2:16, #1 +Counter in file 0 1:1 -> 2:16, #1 Counter in file 0 3:11 -> 3:20, (#1 + #2) Counter in file 0 3:21 -> 4:6, #2 Counter in file 0 5:1 -> 5:2, ((#1 + #2) - #2) Emitting segments for file: ../coverage/while.rs Combined regions: - 2:9 -> 2:16 (count=1) + 1:1 -> 2:16 (count=1) 3:11 -> 3:20 (count=1) 3:21 -> 4:6 (count=0) 5:1 -> 5:2 (count=1) -Segment at 2:9 (count = 1), RegionEntry +Segment at 1:1 (count = 1), RegionEntry Segment at 2:16 (count = 0), Skipped Segment at 3:11 (count = 1), RegionEntry Segment at 3:20 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.while_early_ret.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while_early_ret.txt similarity index 81% rename from src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.while_early_ret.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while_early_ret.txt index f541baec50c0b..12f444945a18a 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.while_early_ret.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while_early_ret.txt @@ -1,24 +1,24 @@ -Counter in file 0 5:9 -> 5:27, #1 +Counter in file 0 4:1 -> 5:27, #1 Counter in file 0 7:9 -> 9:10, (#1 + #2) Counter in file 0 12:13 -> 14:14, ((#1 + #2) - #3) -Counter in file 0 18:21 -> 20:22, #6 +Counter in file 0 18:21 -> 20:22, (((#1 + #2) - #3) - #2) Counter in file 0 22:21 -> 22:27, #4 Counter in file 0 26:21 -> 26:27, #5 -Counter in file 0 30:9 -> 32:10, #2 +Counter in file 0 29:10 -> 32:10, #2 Counter in file 0 35:5 -> 35:11, #3 Counter in file 0 36:1 -> 36:2, ((#4 + #5) + #3) Emitting segments for file: ../coverage/while_early_ret.rs Combined regions: - 5:9 -> 5:27 (count=1) + 4:1 -> 5:27 (count=1) 7:9 -> 9:10 (count=7) 12:13 -> 14:14 (count=7) 18:21 -> 20:22 (count=1) 22:21 -> 22:27 (count=0) 26:21 -> 26:27 (count=1) - 30:9 -> 32:10 (count=6) + 29:10 -> 32:10 (count=6) 35:5 -> 35:11 (count=0) 36:1 -> 36:2 (count=1) -Segment at 5:9 (count = 1), RegionEntry +Segment at 4:1 (count = 1), RegionEntry Segment at 5:27 (count = 0), Skipped Segment at 7:9 (count = 7), RegionEntry Segment at 9:10 (count = 0), Skipped @@ -30,7 +30,7 @@ Segment at 22:21 (count = 0), RegionEntry Segment at 22:27 (count = 0), Skipped Segment at 26:21 (count = 1), RegionEntry Segment at 26:27 (count = 0), Skipped -Segment at 30:9 (count = 6), RegionEntry +Segment at 29:10 (count = 6), RegionEntry Segment at 32:10 (count = 0), Skipped Segment at 35:5 (count = 0), RegionEntry Segment at 35:11 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.yield.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.yield.txt new file mode 100644 index 0000000000000..6ed3e465611e9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.yield.txt @@ -0,0 +1,94 @@ +Counter in file 0 7:1 -> 7:11, #1 +Counter in file 0 8:9 -> 8:22, (#1 + 0) +Counter in file 0 13:11 -> 14:35, (#1 + 0) +Counter in file 0 14:39 -> 14:41, #4 +Counter in file 0 15:14 -> 15:52, (#2 + #3) +Counter in file 0 17:11 -> 17:46, (#4 + 0) +Counter in file 0 18:34 -> 18:39, (#4 - #5) +Counter in file 0 18:44 -> 18:46, ((#4 - #5) - #6) +Counter in file 0 19:14 -> 19:52, (#5 + #6) +Counter in file 0 22:9 -> 22:22, (((#4 - #5) - #6) + 0) +Counter in file 0 29:11 -> 30:35, (((#4 - #5) - #6) + 0) +Counter in file 0 30:39 -> 30:41, #9 +Counter in file 0 31:14 -> 31:52, (#7 + #8) +Counter in file 0 33:11 -> 34:35, (#9 + 0) +Counter in file 0 34:39 -> 34:41, #12 +Counter in file 0 35:14 -> 35:52, (#10 + #11) +Counter in file 0 37:1 -> 37:2, (#12 + 0) +Counter in file 0 8:28 -> 9:16, #1 +Counter in file 0 10:16 -> 11:6, #2 +Counter in file 0 22:28 -> 23:16, #1 +Counter in file 0 24:9 -> 24:16, #2 +Counter in file 0 25:9 -> 25:16, #3 +Counter in file 0 26:16 -> 27:6, #4 +Emitting segments for file: ../coverage/yield.rs +Combined regions: + 7:1 -> 7:11 (count=1) + 8:9 -> 8:22 (count=1) + 8:28 -> 9:16 (count=1) + 10:16 -> 11:6 (count=1) + 13:11 -> 14:35 (count=1) + 14:39 -> 14:41 (count=1) + 15:14 -> 15:52 (count=0) + 17:11 -> 17:46 (count=1) + 18:34 -> 18:39 (count=1) + 18:44 -> 18:46 (count=1) + 19:14 -> 19:52 (count=0) + 22:9 -> 22:22 (count=1) + 22:28 -> 23:16 (count=1) + 24:9 -> 24:16 (count=1) + 25:9 -> 25:16 (count=0) + 26:16 -> 27:6 (count=0) + 29:11 -> 30:35 (count=1) + 30:39 -> 30:41 (count=1) + 31:14 -> 31:52 (count=0) + 33:11 -> 34:35 (count=1) + 34:39 -> 34:41 (count=1) + 35:14 -> 35:52 (count=0) + 37:1 -> 37:2 (count=1) +Segment at 7:1 (count = 1), RegionEntry +Segment at 7:11 (count = 0), Skipped +Segment at 8:9 (count = 1), RegionEntry +Segment at 8:22 (count = 0), Skipped +Segment at 8:28 (count = 1), RegionEntry +Segment at 9:16 (count = 0), Skipped +Segment at 10:16 (count = 1), RegionEntry +Segment at 11:6 (count = 0), Skipped +Segment at 13:11 (count = 1), RegionEntry +Segment at 14:35 (count = 0), Skipped +Segment at 14:39 (count = 1), RegionEntry +Segment at 14:41 (count = 0), Skipped +Segment at 15:14 (count = 0), RegionEntry +Segment at 15:52 (count = 0), Skipped +Segment at 17:11 (count = 1), RegionEntry +Segment at 17:46 (count = 0), Skipped +Segment at 18:34 (count = 1), RegionEntry +Segment at 18:39 (count = 0), Skipped +Segment at 18:44 (count = 1), RegionEntry +Segment at 18:46 (count = 0), Skipped +Segment at 19:14 (count = 0), RegionEntry +Segment at 19:52 (count = 0), Skipped +Segment at 22:9 (count = 1), RegionEntry +Segment at 22:22 (count = 0), Skipped +Segment at 22:28 (count = 1), RegionEntry +Segment at 23:16 (count = 0), Skipped +Segment at 24:9 (count = 1), RegionEntry +Segment at 24:16 (count = 0), Skipped +Segment at 25:9 (count = 0), RegionEntry +Segment at 25:16 (count = 0), Skipped +Segment at 26:16 (count = 0), RegionEntry +Segment at 27:6 (count = 0), Skipped +Segment at 29:11 (count = 1), RegionEntry +Segment at 30:35 (count = 0), Skipped +Segment at 30:39 (count = 1), RegionEntry +Segment at 30:41 (count = 0), Skipped +Segment at 31:14 (count = 0), RegionEntry +Segment at 31:52 (count = 0), Skipped +Segment at 33:11 (count = 1), RegionEntry +Segment at 34:35 (count = 0), Skipped +Segment at 34:39 (count = 1), RegionEntry +Segment at 34:41 (count = 0), Skipped +Segment at 35:14 (count = 0), RegionEntry +Segment at 35:52 (count = 0), Skipped +Segment at 37:1 (count = 1), RegionEntry +Segment at 37:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/prettify_json.py b/src/test/run-make-fulldeps/coverage-reports/prettify_json.py similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/prettify_json.py rename to src/test/run-make-fulldeps/coverage-reports/prettify_json.py diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 2d179aa0f1147..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - -closure.main-{closure#0} - Coverage Spans - - - -
|| - { - let @0⦊mut countdown = 0⦉@0; - if @0⦊is_false⦉@0 @1,3⦊{ - countdown = 10; - }⦉@1,3@2⦊⦉@2 - @4,5⦊"alt string 2".to_owned() - }⦉@4,5
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 0614da6cee27f..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - -closure.main-{closure#2} - Coverage Spans - - - -
|| - { - let @0⦊mut countdown = 0⦉@0; - if @0⦊is_false⦉@0 @1,3⦊{ - countdown = 10; - }⦉@1,3@2⦊⦉@2 - @4,5⦊"alt string 1".to_owned() - }⦉@4,5
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html deleted file mode 100644 index bbafb44017cf9..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - -closure.main-{closure#3} - Coverage Spans - - - -
|| - { - let @0⦊mut countdown = 0⦉@0; - if @0⦊is_false⦉@0 @1,3⦊{ - countdown = 10; - }⦉@1,3@2⦊⦉@2 - @4,5⦊"alt string 3".to_owned() - }⦉@4,5
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 8d1938c0922be..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,4515 +0,0 @@ - - - - -closure.main - Coverage Spans - - - -
fn main() @0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊{ - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - let is_false = ! is_true; - - let mut some_string = Some(String::from("the string content")); - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 1".to_owned() - }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊ - ) - ); - - some_string = Some(String::from("the string content")); - let - a - = - ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 2".to_owned() - }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊; - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - a - ) - ); - - some_string = None; - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 3".to_owned() - }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊ - ) - ); - - some_string = None; - let - a - = - ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 4".to_owned() - }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊; - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - a - ) - ); -}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index cda1040c29114..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,263 +0,0 @@ - - - - -conditions.main - Coverage Spans - - - -
fn main() { - let @0⦊mut countdown = 0⦉@0; - if @0⦊true⦉@0 @1,3⦊{ - countdown = 10; - }⦉@1,3@2⦊⦉@2 - - const B: u32 = 100; - let @25⦊x⦉@25 = if @4⦊countdown > 7⦉@4 { - @8⦊countdown -= 4; - B⦉@8 - } else if @6⦊countdown > 2⦉@6 { - if @9,11⦊countdown < 1⦉@9,11 || @18⦊countdown > 5⦉@18@16⦊⦉@16@17⦊⦉@17 || @14⦊countdown != 9⦉@14@12⦊⦉@12@13⦊⦉@13 @20,22⦊{ - countdown = 0; - }⦉@20,22@21⦊⦉@21 - @24⦊countdown -= 5; - countdown⦉@24 - } else { - @10⦊return⦉@10; - }; - - let @25⦊mut countdown = 0⦉@25; - if @25⦊true⦉@25 @26,28⦊{ - countdown = 10; - }⦉@26,28@27⦊⦉@27 - - if @29⦊countdown > 7⦉@29 { - @33⦊countdown -= 4⦉@33; - } else if @31⦊countdown > 2⦉@31 { - if @34,36⦊countdown < 1⦉@34,36 || @43⦊countdown > 5⦉@43@41⦊⦉@41@42⦊⦉@42 || @39⦊countdown != 9⦉@39@37⦊⦉@37@38⦊⦉@38 @45,47⦊{ - countdown = 0; - }⦉@45,47@46⦊⦉@46 - @49⦊countdown -= 5⦉@49; - } else { - @35⦊return⦉@35; - } - - let @50⦊mut countdown = 0⦉@50; - if @50⦊true⦉@50 @51,53⦊{ - countdown = 1; - }⦉@51,53@52⦊⦉@52 - - let @77⦊z⦉@77 = if @54⦊countdown > 7⦉@54 { - @58⦊countdown -= 4⦉@58; - } else if @56⦊countdown > 2⦉@56 { - if @59,61⦊countdown < 1⦉@59,61 || @68⦊countdown > 5⦉@68@66⦊⦉@66@67⦊⦉@67 || @64⦊countdown != 9⦉@64@62⦊⦉@62@63⦊⦉@63 @70,72⦊{ - countdown = 0; - }⦉@70,72@71⦊⦉@71 - @74⦊countdown -= 5⦉@74; - } else { - let @60,75,76⦊should_be_reachable = countdown; - println!("reached"); - return⦉@60,75,76; - }; - - let @98⦊w⦉@98 = if @77⦊countdown > 7⦉@77 { - @81⦊countdown -= 4⦉@81; - } else if @79⦊countdown > 2⦉@79 { - if @82,84⦊countdown < 1⦉@82,84 || @91⦊countdown > 5⦉@91@89⦊⦉@89@90⦊⦉@90 || @87⦊countdown != 9⦉@87@85⦊⦉@85@86⦊⦉@86 @93,95⦊{ - countdown = 0; - }⦉@93,95@94⦊⦉@94 - @97⦊countdown -= 5⦉@97; - } else { - @83⦊return⦉@83; - }; -}@101⦊⦉@101@102⦊⦉@102
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 80a3d52fe43c9..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - -generics.main - Coverage Spans - - - -
fn main() -> Result<(),u8> { - let @0,1,2,3⦊mut firecracker = Firework { strength: 1 }; - firecracker.set_strength(2); - - let mut tnt = Firework { strength: 100.1 }; - tnt.set_strength(200.1); - tnt.set_strength(300.3)⦉@0,1,2,3; - - if @0,1,2,3⦊true⦉@0,1,2,3 { - @4,6,7,8,12,13⦊println!("Exiting with error..."); - return Err(1)⦉@4,6,7,8,12,13; - } - - let _ = @5,9,10,11⦊Firework { strength: 1000 }; - - Ok(())⦉@5,9,10,11 -}@14⦊⦉@14
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 77983f8539086..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - -if.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let - @0,1,2,3⦊is_true - = - std::env::args().len() - == - 1 - ; - let - mut - countdown - = - 0⦉@0,1,2,3 - ; - if - @0,1,2,3⦊is_true⦉@0,1,2,3 - @4,6⦊{ - countdown - = - 10 - ; - }⦉@4,6@5⦊⦉@5 -}@7⦊⦉@7
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 8716ac45d5714..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - -if_else.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - - let mut countdown = 0; - if - is_true⦉@0,1,2,3 - @4,6⦊{ - countdown - = - 10 - ; - }⦉@4,6 - else // Note coverage region difference without semicolon - { - @5⦊countdown - = - 100⦉@5 - } - - if - @7⦊is_true⦉@7 - @8,10⦊{ - countdown - = - 10 - ; - }⦉@8,10 - else - @9⦊{ - countdown - = - 100 - ; - }⦉@9 -}@11⦊⦉@11
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html deleted file mode 100644 index 31bb57be81b53..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - -inner_items.main-in_func - Coverage Spans - - - -
fn in_func(a: u32) { - let @0⦊b = 1⦉@0; - let @1,2,3,4⦊c⦉@1,2,3,4 = @0⦊a + b⦉@0; - @1,2,3,4⦊println!("c = {}", c) - }⦉@1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 0388ca42ac88b..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - -lazy_boolean.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - - let (mut a, mut b, mut c) = (0, 0, 0)⦉@0,1,2,3; - if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ - a = 1; - b = 10; - c = 100; - }⦉@4,6@5⦊⦉@5 - let - @11⦊somebool⦉@11 - = - @7⦊a < b⦉@7 - || - @10⦊b < c⦉@10@8⦊⦉@8@9⦊⦉@9 - ; - let - @15⦊somebool⦉@15 - = - @11⦊b < a⦉@11 - || - @14⦊b < c⦉@14@12⦊⦉@12@13⦊⦉@13 - ; - let @19⦊somebool⦉@19 = @15⦊a < b⦉@15 && @18⦊b < c⦉@18@16⦊⦉@16@17⦊⦉@17; - let @23⦊somebool⦉@23 = @19⦊b < a⦉@19 && @22⦊b < c⦉@22@20⦊⦉@20@21⦊⦉@21; - - if - @23⦊! - is_true⦉@23 - @24,26⦊{ - a = 2 - ; - }⦉@24,26@25⦊⦉@25 - - if - @27⦊is_true⦉@27 - @28,30⦊{ - b = 30 - ; - }⦉@28,30 - else - @29⦊{ - c = 400 - ; - }⦉@29 - - if @31⦊!is_true⦉@31 @32,34⦊{ - a = 2; - }⦉@32,34@33⦊⦉@33 - - if @35⦊is_true⦉@35 @36,38⦊{ - b = 30; - }⦉@36,38 else @37⦊{ - c = 400; - }⦉@37 -}@39⦊⦉@39
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 941bfca76f321..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - -loop_break_value.main - Coverage Spans - - - -
fn main() @0,1⦊{ - let result - = - loop - { - break - 10 - ; - } - ; -}⦉@0,1
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#0}-new.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#0}-new.-------.InstrumentCoverage.0.html deleted file mode 100644 index a3c98e97bbd87..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#0}-new.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - -partial_eq.{impl#0}-new - Coverage Spans - - - -
pub fn new(major: usize, minor: usize, patch: usize) -> Self { - @0⦊Self { - major, - minor, - patch, - } - }⦉@0
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 5399895992e11..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - -partial_eq.{impl#2}-ge-{closure#0} - Coverage Spans - - - -
major: usize, - @0,1,2,3⦊⦉@0,1,2,3minor: usize
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 30047ab79725b..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - -partial_eq.{impl#2}-gt-{closure#0}-{closure#0} - Coverage Spans - - - -
minor: usize, - @0,1,2⦊patch: usize⦉@0,1,2
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt.-------.InstrumentCoverage.0.html deleted file mode 100644 index f1f78e4663949..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - -partial_eq.{impl#2}-gt - Coverage Spans - - - -
@0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd@0,1,2,3,4⦊⦉@0,1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le.-------.InstrumentCoverage.0.html deleted file mode 100644 index 49ebcfaafb54e..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - -partial_eq.{impl#2}-le - Coverage Spans - - - -
@0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd@0,1,2,3,4⦊⦉@0,1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 812dc622ec038..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - -partial_eq.{impl#2}-lt-{closure#0} - Coverage Spans - - - -
major: usize, - @0,1,2,3⦊⦉@0,1,2,3minor: usize
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt.-------.InstrumentCoverage.0.html deleted file mode 100644 index 742b45773232b..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - -partial_eq.{impl#2}-lt - Coverage Spans - - - -
@0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd@0,1,2,3,4⦊⦉@0,1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html deleted file mode 100644 index 3714c774bae3f..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - -partial_eq.{impl#2}-partial_cmp - Coverage Spans - - - -
@17⦊@14,15⦊@16⦊PartialOrd⦉@16⦉@14,15⦉@17@18⦊⦉@18
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html deleted file mode 100644 index be1f7f7d2e726..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - -partial_eq.{impl#6}-ne - Coverage Spans - - - -
@2⦊@5⦊@6⦊@1⦊PartialEq⦉@1⦉@6⦉@5⦉@2@4⦊⦉@4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 914e829faa0bd..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - -simple_loop.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - - let mut countdown = 0⦉@0,1,2,3; - - if - @0,1,2,3⦊is_true⦉@0,1,2,3 - @4,6⦊{ - countdown - = - 10 - ; - }⦉@4,6@5⦊⦉@5 - - loop - { - if - @8,9⦊countdown - == - 0⦉@8,9 - { - @10,12⦊break⦉@10,12 - ; - } - @13⦊countdown - -= - 1⦉@13 - ; - }@7⦊⦉@7 -}@10,12⦊⦉@10,12
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 5c9baee5d8050..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - -try_error_result.main - Coverage Spans - - - -
fn main() -> Result<(),()> { - let @0,1⦊mut - countdown = 10⦉@0,1 - ; - for - @6,8⦊_⦉@6,8 - in - @2,3,4⦊0..10⦉@2,3,4 - { - @9⦊countdown - -= 1 - ; - if - countdown < 5⦉@9 - { - @10,12,13,14⦊call(/*return_error=*/ true)⦉@10,12,13,14@16,18,19,20⦊?⦉@16,18,19,20; - @15,21,22⦊call(/*return_error=*/ false)⦉@15,21,22@24,26,27,28⦊?⦉@24,26,27,28; - } - else - { - @11,29,30⦊call(/*return_error=*/ false)⦉@11,29,30@32,34,35,36⦊?⦉@32,34,35,36; - }@23⦊⦉@23@31⦊⦉@31 - }@37⦊⦉@37 - @5⦊Ok(())⦉@5 -}@38⦊⦉@38@39⦊⦉@39
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 765e3b62c11c2..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - -while_early_ret.main - Coverage Spans - - - -
fn main() -> Result<(),u8> { - let @0⦊mut countdown = 10⦉@0; - while - @1,2⦊countdown - > - 0⦉@1,2 - { - if - @3,5⦊countdown - < - 5⦉@3,5 - { - return - if - @6,8⦊countdown - > - 8⦉@6,8 - { - @9,11⦊Ok(())⦉@9,11 - } - else - { - @10⦊Err(1)⦉@10 - } - ; - } - @12⦊countdown - -= - 1⦉@12 - ; - } - @4⦊Ok(())⦉@4 -}@13⦊⦉@13@14⦊⦉@14
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/Makefile b/src/test/run-make-fulldeps/coverage-spanview-deadcode/Makefile deleted file mode 100644 index 826e85b35e5ff..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# needs-profiler-support -# ignore-msvc - -# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 -LINK_DEAD_CODE=yes - --include ../coverage-spanview-base/Makefile - -# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and -# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. -# See ../coverage/coverage_tools.mk for more information. diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 58e81a221d3a8..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - -closure.main-{closure#1} - Coverage Spans - - - -
|| - { - let @0⦊mut countdown = 0⦉@0; - if @0⦊is_false⦉@0 @1,3⦊{ - countdown = 10; - }⦉@1,3@2⦊⦉@2 - @4,5⦊"alt string 4".to_owned() - }⦉@4,5
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 8d1938c0922be..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,4515 +0,0 @@ - - - - -closure.main - Coverage Spans - - - -
fn main() @0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊{ - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - let is_false = ! is_true; - - let mut some_string = Some(String::from("the string content")); - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 1".to_owned() - }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊ - ) - ); - - some_string = Some(String::from("the string content")); - let - a - = - ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 2".to_owned() - }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊; - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - a - ) - ); - - some_string = None; - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 3".to_owned() - }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊ - ) - ); - - some_string = None; - let - a - = - ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 4".to_owned() - }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊; - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - a - ) - ); -}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index cda1040c29114..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,263 +0,0 @@ - - - - -conditions.main - Coverage Spans - - - -
fn main() { - let @0⦊mut countdown = 0⦉@0; - if @0⦊true⦉@0 @1,3⦊{ - countdown = 10; - }⦉@1,3@2⦊⦉@2 - - const B: u32 = 100; - let @25⦊x⦉@25 = if @4⦊countdown > 7⦉@4 { - @8⦊countdown -= 4; - B⦉@8 - } else if @6⦊countdown > 2⦉@6 { - if @9,11⦊countdown < 1⦉@9,11 || @18⦊countdown > 5⦉@18@16⦊⦉@16@17⦊⦉@17 || @14⦊countdown != 9⦉@14@12⦊⦉@12@13⦊⦉@13 @20,22⦊{ - countdown = 0; - }⦉@20,22@21⦊⦉@21 - @24⦊countdown -= 5; - countdown⦉@24 - } else { - @10⦊return⦉@10; - }; - - let @25⦊mut countdown = 0⦉@25; - if @25⦊true⦉@25 @26,28⦊{ - countdown = 10; - }⦉@26,28@27⦊⦉@27 - - if @29⦊countdown > 7⦉@29 { - @33⦊countdown -= 4⦉@33; - } else if @31⦊countdown > 2⦉@31 { - if @34,36⦊countdown < 1⦉@34,36 || @43⦊countdown > 5⦉@43@41⦊⦉@41@42⦊⦉@42 || @39⦊countdown != 9⦉@39@37⦊⦉@37@38⦊⦉@38 @45,47⦊{ - countdown = 0; - }⦉@45,47@46⦊⦉@46 - @49⦊countdown -= 5⦉@49; - } else { - @35⦊return⦉@35; - } - - let @50⦊mut countdown = 0⦉@50; - if @50⦊true⦉@50 @51,53⦊{ - countdown = 1; - }⦉@51,53@52⦊⦉@52 - - let @77⦊z⦉@77 = if @54⦊countdown > 7⦉@54 { - @58⦊countdown -= 4⦉@58; - } else if @56⦊countdown > 2⦉@56 { - if @59,61⦊countdown < 1⦉@59,61 || @68⦊countdown > 5⦉@68@66⦊⦉@66@67⦊⦉@67 || @64⦊countdown != 9⦉@64@62⦊⦉@62@63⦊⦉@63 @70,72⦊{ - countdown = 0; - }⦉@70,72@71⦊⦉@71 - @74⦊countdown -= 5⦉@74; - } else { - let @60,75,76⦊should_be_reachable = countdown; - println!("reached"); - return⦉@60,75,76; - }; - - let @98⦊w⦉@98 = if @77⦊countdown > 7⦉@77 { - @81⦊countdown -= 4⦉@81; - } else if @79⦊countdown > 2⦉@79 { - if @82,84⦊countdown < 1⦉@82,84 || @91⦊countdown > 5⦉@91@89⦊⦉@89@90⦊⦉@90 || @87⦊countdown != 9⦉@87@85⦊⦉@85@86⦊⦉@86 @93,95⦊{ - countdown = 0; - }⦉@93,95@94⦊⦉@94 - @97⦊countdown -= 5⦉@97; - } else { - @83⦊return⦉@83; - }; -}@101⦊⦉@101@102⦊⦉@102
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index aebeb39fd5179..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - -drop_trait.main - Coverage Spans - - - -
fn main() -> Result<(),u8> { - let @0⦊_firecracker = Firework { strength: 1 }; - - let _tnt = Firework { strength: 100 }⦉@0; - - if @0⦊true⦉@0 { - @1,3,4,5,9,10⦊println!("Exiting with error..."); - return Err(1)⦉@1,3,4,5,9,10; - } - - let _ = @2,6,7,8⦊Firework { strength: 1000 }; - - Ok(())⦉@2,6,7,8 -}@11⦊⦉@11
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html deleted file mode 100644 index 577491a4e247c..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - -drop_trait.{impl#0}-drop - Coverage Spans - - - -
fn drop(&mut self) @0,1,2,3⦊{ - println!("BOOM times {}!!!", self.strength); - }⦉@0,1,2,3
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html deleted file mode 100644 index bfd7f6b4bb5a0..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - -generics.{impl#0}-set_strength - Coverage Spans - - - -
fn set_strength(&mut self, new_strength: T) @0⦊{ - self.strength = new_strength; - }⦉@0
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html deleted file mode 100644 index 58a528e341bef..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - -generics.{impl#1}-drop - Coverage Spans - - - -
fn drop(&mut self) @0,1,2,3⦊{ - println!("BOOM times {}!!!", self.strength); - }⦉@0,1,2,3
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html deleted file mode 100644 index 31bb57be81b53..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - -inner_items.main-in_func - Coverage Spans - - - -
fn in_func(a: u32) { - let @0⦊b = 1⦉@0; - let @1,2,3,4⦊c⦉@1,2,3,4 = @0⦊a + b⦉@0; - @1,2,3,4⦊println!("c = {}", c) - }⦉@1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 815d5efbce69f..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - -inner_items.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - - let mut countdown = 0⦉@0,1,2,3; - if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ - countdown = 10; - }⦉@4,6@5⦊⦉@5 - - mod in_mod { - const IN_MOD_CONST: u32 = 1000; - } - - fn in_func(a: u32) { - let b = 1; - let c = a + b; - println!("c = {}", c) - } - - struct InStruct { - in_struct_field: u32, - } - - const IN_CONST: u32 = 1234; - - trait InTrait { - fn trait_func(&mut self, incr: u32); - - fn default_trait_func(&mut self) { - in_func(IN_CONST); - self.trait_func(IN_CONST); - } - } - - impl InTrait for InStruct { - fn trait_func(&mut self, incr: u32) { - self.in_struct_field += incr; - in_func(self.in_struct_field); - } - } - - type InType = String; - - if @7⦊is_true⦉@7 @8,10,11⦊{ - in_func(countdown); - }⦉@8,10,11@9⦊⦉@9 - - let @12,13⦊mut val = InStruct { - in_struct_field: 101, - }; - - val.default_trait_func(); -}⦉@12,13
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index f1488d644d044..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - -loops_branches.main - Coverage Spans - - - -
fn main() @0,1,2,3⦊{ - let debug_test = DebugTest; - println!("{:?}", debug_test); -}⦉@0,1,2,3
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.{impl#0}-fmt.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.{impl#0}-fmt.-------.InstrumentCoverage.0.html deleted file mode 100644 index 334a64b0bb8f9..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.{impl#0}-fmt.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - -loops_branches.{impl#0}-fmt - Coverage Spans - - - -
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if @0⦊true⦉@0 { - if @1,3⦊false⦉@1,3 { - while @6,7⦊true⦉@6,7 @8,10⦊{ - }⦉@8,10 - }@9⦊⦉@9@5⦊⦉@5 - @11,12,13,14⦊write!(f, "error")⦉@11,12,13,14@16,18,19,20⦊?⦉@16,18,19,20; - } else @2⦊{ - }⦉@2@15⦊⦉@15 - @21⦊Ok(())⦉@21 - }@22⦊⦉@22
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 7fbda5d0b3d2c..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,135 +0,0 @@ - - - - -nested_loops.main - Coverage Spans - - - -
fn main() { - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - let mut countdown = 10⦉@0,1,2,3; - - 'outer: while @4,5⦊countdown > 0⦉@4,5 { - let @6,8,9⦊mut a = 100; - let mut b = 100⦉@6,8,9; - for @14,16⦊_⦉@14,16 in @10,11,12⦊0..50⦉@10,11,12 { - if @14,16⦊a < 30⦉@14,16 { - @17,19⦊break⦉@17,19; - } - @20⦊a -= 5⦉@20; - @21⦊b -= 5⦉@21; - if @21⦊b < 90⦉@21 { - @25⦊a -= 10; - if is_true⦉@25 { - @26,28⦊break 'outer⦉@26,28; - } else { - @29⦊a -= 2; - } - }⦉@29@23⦊⦉@23 - }@30⦊⦉@30 - @32⦊countdown -= 1⦉@32; - }@7⦊⦉@7 -}@33⦊⦉@33
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index a7830911376bf..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,295 +0,0 @@ - - - - -partial_eq.main - Coverage Spans - - - -
fn main() @0,1,2,3,4,5,6,7,8⦊{ - let version_3_2_1 = Version::new(3, 2, 1); - let version_3_3_0 = Version::new(3, 3, 0); - - println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); -}⦉@0,1,2,3,4,5,6,7,8
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html deleted file mode 100644 index 1a40b30099da6..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - -partial_eq.{impl#1}-cmp - Coverage Spans - - - -
@14⦊@11,12⦊@13⦊Ord⦉@13⦉@11,12⦉@14@15⦊⦉@15
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge.-------.InstrumentCoverage.0.html deleted file mode 100644 index 044dd7eb9f577..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - -partial_eq.{impl#2}-ge - Coverage Spans - - - -
@0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd@0,1,2,3,4⦊⦉@0,1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 00b5d91b1cf91..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - -partial_eq.{impl#2}-gt-{closure#0} - Coverage Spans - - - -
major: usize, - @0,1,2,3⦊⦉@0,1,2,3minor: usize
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index e8da313d18e08..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - -partial_eq.{impl#2}-le-{closure#0}-{closure#0} - Coverage Spans - - - -
minor: usize, - @0,1,2⦊patch: usize⦉@0,1,2
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 55438a463c420..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - -partial_eq.{impl#2}-lt-{closure#0}-{closure#0} - Coverage Spans - - - -
minor: usize, - @0,1,2⦊patch: usize⦉@0,1,2
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html deleted file mode 100644 index 3714c774bae3f..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - -partial_eq.{impl#2}-partial_cmp - Coverage Spans - - - -
@17⦊@14,15⦊@16⦊PartialOrd⦉@16⦉@14,15⦉@17@18⦊⦉@18
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html deleted file mode 100644 index be1f7f7d2e726..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - -partial_eq.{impl#6}-ne - Coverage Spans - - - -
@2⦊@5⦊@6⦊@1⦊PartialEq⦉@1⦉@6⦉@5⦉@2@4⦊⦉@4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html deleted file mode 100644 index 65b95bae78d6e..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,109 +0,0 @@ - - - - -partial_eq.{impl#7}-fmt - Coverage Spans - - - -
@0,1,2,3,4,5⦊Debug⦉@0,1,2,3,4,5
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 914e829faa0bd..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - -simple_loop.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - - let mut countdown = 0⦉@0,1,2,3; - - if - @0,1,2,3⦊is_true⦉@0,1,2,3 - @4,6⦊{ - countdown - = - 10 - ; - }⦉@4,6@5⦊⦉@5 - - loop - { - if - @8,9⦊countdown - == - 0⦉@8,9 - { - @10,12⦊break⦉@10,12 - ; - } - @13⦊countdown - -= - 1⦉@13 - ; - }@7⦊⦉@7 -}@10,12⦊⦉@10,12
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 2488ac563e77e..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,188 +0,0 @@ - - - - -simple_match.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - - let mut countdown = 1⦉@0,1,2,3; - if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ - countdown = 0; - }⦉@4,6@5⦊⦉@5 - - for - @13,15,17⦊_⦉@13,15,17 - in - @9,10,11⦊0..2⦉@9,10,11 - { - let z - ; - match - @13,15,17⦊countdown⦉@13,15,17 - { - @18⦊x⦉@18 - if - @13,15,17⦊x - < - 1⦉@13,15,17@19⦊⦉@19 - => - @18⦊{ - z = countdown - ; - let y = countdown - ; - countdown = 10 - ; - }⦉@18 - _ - => - @16⦊{}⦉@16 - } - }@7,8⦊⦉@7,8@20⦊⦉@20 -}@12⦊⦉@12
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 3ba5135122b93..0000000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - -while.main - Coverage Spans - - - -
fn main() { - let @0⦊num = 9⦉@0; - while @1,2⦊num >= 10⦉@1,2 @3,5⦊{ - }⦉@3,5 -}@4⦊⦉@4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/Makefile b/src/test/run-make-fulldeps/coverage-spanview/Makefile similarity index 50% rename from src/test/run-make-fulldeps/coverage-spanview-base/Makefile rename to src/test/run-make-fulldeps/coverage-spanview/Makefile index 9f9440340e0ed..84b5d0e522f8c 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/Makefile +++ b/src/test/run-make-fulldeps/coverage-spanview/Makefile @@ -1,12 +1,8 @@ # needs-profiler-support -# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and -# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. -# See ../coverage/coverage_tools.mk for more information. - -include ../coverage/coverage_tools.mk -BASEDIR=../coverage-spanview-base +BASEDIR=../coverage-spanview SOURCEDIR=../coverage define SPANVIEW_HEADER @@ -14,7 +10,7 @@ define SPANVIEW_HEADER + + +abort.main - Coverage Spans + + + +
@0⦊fn main() -> Result<(), u8> { + let mut countdown = 10⦉@0; + while @1,2⦊countdown > 0⦉@1,2 { + if @3,5⦊countdown < 5⦉@3,5 @6,8,9⦊{ + might_abort(false); + }⦉@6,8,9@7⦊⦉@7 + // See discussion (below the `Notes` section) on coverage results for the closing brace. + if @10⦊countdown < 5⦉@10 @11,13,14⦊{ might_abort(false); }⦉@11,13,14@12⦊⦉@12 // Counts for different regions on one line. + // For the following example, the closing brace is the last character on the line. + // This shows the character after the closing brace is highlighted, even if that next + // character is a newline. + if @15⦊countdown < 5⦉@15 @16,18,19⦊{ might_abort(false); }⦉@16,18,19@17⦊⦉@17 + @20,21⦊countdown -= 1⦉@20,21; + } + @4⦊Ok(()) +}⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..ab7108ae570b7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html @@ -0,0 +1,164 @@ + + + + +abort.might_abort - Coverage Spans + + + +
@0⦊fn might_abort(should_abort: bool) ⦉@0{ + if @0⦊should_abort⦉@0 { + @1,3,4,5⦊println!("aborting..."); + panic!("panics and aborts");⦉@1,3,4,5 + } else @2,6,7⦊{ + println!("Don't Panic"); + } +}⦉@2,6,7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..f24de8e08432a --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,104 @@ + + + + +assert.main - Coverage Spans + + + +
@0⦊fn main() -> Result<(),u8> { + let mut countdown = 10⦉@0; + while @1,2⦊countdown > 0⦉@1,2 { + if @3,5⦊countdown == 1⦉@3,5 @6,8,9⦊{ + might_fail_assert(3); + }⦉@6,8,9 else if @7⦊countdown < 5⦉@7 @10,12,13⦊{ + might_fail_assert(2); + }⦉@10,12,13@11⦊⦉@11 + @15,16⦊countdown -= 1⦉@15,16; + } + @4⦊Ok(()) +}⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..13cfebfe6e50e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html @@ -0,0 +1,97 @@ + + + + +assert.might_fail_assert - Coverage Spans + + + +
@0,1,2,3,4⦊fn might_fail_assert(one_plus_one: u32) ⦉@0,1,2,3,4{ + @0,1,2,3,4⦊println!("does 1 + 1 = {}?", one_plus_one);⦉@0,1,2,3,4 + assert_eq!(@0,1,2,3,4⦊1 + 1⦉@0,1,2,3,4, one_plus_one, @5,7,8,9,10,11,12⦊"the argument was wrong"⦉@5,7,8,9,10,11,12); +}@6⦊⦉@6
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c-{closure#0}.-------.InstrumentCoverage.0.html similarity index 63% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c-{closure#0}.-------.InstrumentCoverage.0.html index dfe2eb073aa18..82a22ccb4e673 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c-{closure#0}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -try_error_result.call - Coverage Spans +async.c-{closure#0} - Coverage Spans -
fn call(return_error: bool) -> Result<(),()> { - if @0⦊return_error⦉@0 { - @1,3⦊Err(())⦉@1,3 +
@0⦊{ + if x == 8⦉@0 { + @1,3⦊1⦉@1,3 } else { - @2⦊Ok(())⦉@2 + @2⦊0⦉@2 } -}@4⦊⦉@4
+}@4⦊⦉@4
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..3eee0dd4100ed --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c.-------.InstrumentCoverage.0.html @@ -0,0 +1,80 @@ + + + + +async.c - Coverage Spans + + + +
@0,1⦊async fn c(x: u8) -> u8 ⦉@0,1{ + if x == 8 { + 1 + } else { + 0 + } +}
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d-{closure#0}.-------.InstrumentCoverage.0.html similarity index 75% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d-{closure#0}.-------.InstrumentCoverage.0.html index b908a35f1b799..7cf34f077954f 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d-{closure#0}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -partial_eq.{impl#4}-assert_receiver_is_total_eq - Coverage Spans +async.d-{closure#0} - Coverage Spans -
@0⦊Eq⦉@0
+
@0⦊⦉@0{ 1 }
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..5c7f6e00224a0 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d.-------.InstrumentCoverage.0.html @@ -0,0 +1,74 @@ + + + + +async.d - Coverage Spans + + + +
@0,1⦊async fn d() -> u8 ⦉@0,1{ 1 }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..1f95a7d35af88 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.e-{closure#0} - Coverage Spans + + + +
@0⦊⦉@0{ 1 }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..ee3b7b1d7ffc7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e.-------.InstrumentCoverage.0.html @@ -0,0 +1,74 @@ + + + + +async.e - Coverage Spans + + + +
@0,1⦊async fn e() -> u8 ⦉@0,1{ 1 }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html similarity index 55% rename from src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html index 1a40b30099da6..8f61257ca1bac 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -partial_eq.{impl#1}-cmp - Coverage Spans +async.executor-block_on-VTABLE-{closure#0} - Coverage Spans -
@14⦊@11,12⦊@13⦊Ord⦉@13⦉@11,12⦉@14@15⦊⦉@15
+
@0,1,2,3⦊⦉@0,1,2,3$crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+))
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html similarity index 55% rename from src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html index 0fa59ade1398d..923c669e72d11 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -partial_eq.{impl#2}-ge-{closure#0}-{closure#0} - Coverage Spans +async.executor-block_on-VTABLE-{closure#1} - Coverage Spans -
minor: usize, - @0,1,2⦊patch: usize⦉@0,1,2
+
@0,1,2,3⦊⦉@0,1,2,3$crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+))
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..59f62959998ce --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html @@ -0,0 +1,84 @@ + + + + +async.executor-block_on-VTABLE-{closure#2} - Coverage Spans + + + +
@0,1,2,3⦊⦉@0,1,2,3$crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+))
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..ef2fe7d06825d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.executor-block_on-VTABLE-{closure#3} - Coverage Spans + + + +
|_| @0⦊()⦉@0
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..19707255d07c7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html @@ -0,0 +1,239 @@ + + + + +async.executor-block_on - Coverage Spans + + + +
@0,1,2,3,4,5⦊pub fn block_on<F: Future>(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unimplemented!("clone"), + |_| unimplemented!("wake"), + |_| unimplemented!("wake_by_ref"), + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker)⦉@0,1,2,3,4,5; + + loop { + if let Poll::Ready(@10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17) = @6,7,8,9⦊future.as_mut().poll(&mut context)⦉@6,7,8,9 { + break @10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17; + }@11,13⦊⦉@11,13 + } + }@10,12,14,15,16,17⦊⦉@10,12,14,15,16,17
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..74b62673ac94b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.f-{closure#0} - Coverage Spans + + + +
@0⦊⦉@0{ 1 }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..a31bca54df2e5 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html @@ -0,0 +1,74 @@ + + + + +async.f - Coverage Spans + + + +
@0,1⦊async fn f() -> u8 ⦉@0,1{ 1 }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..b8c53cccabda1 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.foo-{closure#0} - Coverage Spans + + + +
@0⦊⦉@0{ [false; 10] }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..cf72a9d532c79 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html @@ -0,0 +1,74 @@ + + + + +async.foo - Coverage Spans + + + +
@0,1⦊async fn foo() -> [bool; 10] ⦉@0,1{ [false; 10] }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..b10012621b7dd --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,82 @@ + + + + +async.g-{closure#0} - Coverage Spans + + + +
@0,3,4⦊{ + match x⦉@0,3,4 { + @17⦊y⦉@17 if @0,3,4⦊e()⦉@0,3,4.await == @10,13,15,16⦊y⦉@10,13,15,16 => @17⦊()⦉@17, + @33⦊y⦉@33 if @1,19,20⦊f()⦉@1,19,20.await == @26,29,31,32⦊y⦉@26,29,31,32 => @33⦊()⦉@33, + _ => @2⦊()⦉@2, + } +}@35,36⦊⦉@35,36
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..973995477b9aa --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html @@ -0,0 +1,80 @@ + + + + +async.g - Coverage Spans + + + +
@0,1⦊pub async fn g(x: u8) ⦉@0,1{ + match x { + y if e().await == y => (), + y if f().await == y => (), + _ => (), + } +}
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..6b4b43f836580 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,82 @@ + + + + +async.h-{closure#0} - Coverage Spans + + + +
@0,2,3⦊{ // The function signature is counted when called, but the body is not + // executed (not awaited) so the open brace has a `0` count (at least when + // displayed with `llvm-cov show` in color-mode). + match x⦉@0,2,3 { + @17⦊y⦉@17 if @0,2,3⦊foo()⦉@0,2,3.await[@9,12,14,15,16⦊y⦉@9,12,14,15,16] => @17⦊()⦉@17, + _ => @1⦊()⦉@1, + } +}@19,20⦊⦉@19,20
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html similarity index 60% rename from src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html index 6c4ce72305e53..f2ea01281fe1e 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -inner_items.main-{impl#0}-trait_func - Coverage Spans +async.h - Coverage Spans -
fn trait_func(&mut self, incr: u32) { - self.in_struct_field += @0⦊incr⦉@0; - @1,2⦊in_func(self.in_struct_field); - }⦉@1,2
+
@0,1⦊async fn h(x: usize) ⦉@0,1{ // The function signature is counted when called, but the body is not + // executed (not awaited) so the open brace has a `0` count (at least when + // displayed with `llvm-cov show` in color-mode). + match x { + y if foo().await[y] => (), + _ => (), + } +}
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..49297870fa0a7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,91 @@ + + + + +async.i-{closure#0} - Coverage Spans + + + +
@0,3,4⦊{ // line coverage is 1, but there are 2 regions: + // (a) the function signature, counted when the function is called; and + // (b) the open brace for the function body, counted once when the body is + // executed asynchronously. + match x⦉@0,3,4 { + @18,20⦊y⦉@18,20 if @0,3,4⦊c(x)⦉@0,3,4.await == @10,13,15,16,17⦊y + 1⦉@10,13,15,16,17 => { @18,20⦊d()⦉@18,20.await; } + @48⦊y⦉@48 if @1,33,34⦊f()⦉@1,33,34.await == @40,43,45,46,47⦊y + 1⦉@40,43,45,46,47 => @48⦊()⦉@48, + _ => @2⦊()⦉@2, + } +}@50,51⦊⦉@50,51
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html similarity index 59% rename from src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html index 033707a87bb69..e5dc6ecd4eb63 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -tight_inf_loop.main - Coverage Spans +async.i - Coverage Spans -
fn main() { - if @0⦊false⦉@0 { - @4,5⦊loop {}⦉@4,5@1,3⦊⦉@1,3 +
@0,1⦊async fn i(x: u8) ⦉@0,1{ // line coverage is 1, but there are 2 regions: + // (a) the function signature, counted when the function is called; and + // (b) the open brace for the function body, counted once when the body is + // executed asynchronously. + match x { + y if c(x).await == y + 1 => { d().await; } + y if f().await == y + 1 => (), + _ => (), } -}@2⦊⦉@2
+}
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-c.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-c.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..a8e2d7e2f396e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-c.-------.InstrumentCoverage.0.html @@ -0,0 +1,92 @@ + + + + +async.j-c - Coverage Spans + + + +
@0⦊fn c(x: u8) -> u8 { + if x == 8⦉@0 { + @1,3⦊1⦉@1,3 // This line appears covered, but the 1-character expression span covering the `1` + // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because + // `fn j()` executes the open brace for the funciton body, followed by the function's + // first executable statement, `match x`. Inner function declarations are not + // "visible" to the MIR for `j()`, so the code region counts all lines between the + // open brace and the first statement as executed, which is, in a sense, true. + // `llvm-cov show` overcomes this kind of situation by showing the actual counts + // of the enclosed coverages, (that is, the `1` expression was not executed, and + // accurately displays a `0`). + } else { + @2⦊0⦉@2 + } + }@4⦊⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-d.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-d.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..4eed8ee60dd64 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-d.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.j-d - Coverage Spans + + + +
@0⦊fn d() -> u8 { 1 }⦉@0
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-f.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-f.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..6e80c8c786ecb --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-f.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.j-f - Coverage Spans + + + +
@0⦊fn f() -> u8 { 1 }⦉@0
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..7cc751074a077 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j.-------.InstrumentCoverage.0.html @@ -0,0 +1,108 @@ + + + + +async.j - Coverage Spans + + + +
@0,3,4,5⦊fn j(x: u8) { + // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`. + fn c(x: u8) -> u8 { + if x == 8 { + 1 // This line appears covered, but the 1-character expression span covering the `1` + // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because + // `fn j()` executes the open brace for the funciton body, followed by the function's + // first executable statement, `match x`. Inner function declarations are not + // "visible" to the MIR for `j()`, so the code region counts all lines between the + // open brace and the first statement as executed, which is, in a sense, true. + // `llvm-cov show` overcomes this kind of situation by showing the actual counts + // of the enclosed coverages, (that is, the `1` expression was not executed, and + // accurately displays a `0`). + } else { + 0 + } + } + fn d() -> u8 { 1 } + fn f() -> u8 { 1 } + match x⦉@0,3,4,5 { + @6,8⦊y⦉@6,8 if @0,3,4,5⦊c(x) == y + 1⦉@0,3,4,5 => @6,8⦊{ d(); }⦉@6,8 + @12⦊y⦉@12 if @1,9,10,11⦊f() == y + 1⦉@1,9,10,11 => @12⦊()⦉@12, + _ => @2⦊()⦉@2, + } +}@14⦊⦉@14
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.k.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.k.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..5792521bb2c57 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.k.-------.InstrumentCoverage.0.html @@ -0,0 +1,80 @@ + + + + +async.k - Coverage Spans + + + +
@0⦊fn k(x: u8) { // unused function + match x⦉@0 { + 1 => @1,4⦊()⦉@1,4, + 2 => @2,5⦊()⦉@2,5, + _ => @3⦊()⦉@3, + } +}@6⦊⦉@6
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.l.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.l.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..cd92b88c24cbb --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.l.-------.InstrumentCoverage.0.html @@ -0,0 +1,80 @@ + + + + +async.l - Coverage Spans + + + +
@0⦊fn l(x: u8) { + match x⦉@0 { + 1 => @1,4⦊()⦉@1,4, + 2 => @2,5⦊()⦉@2,5, + _ => @3⦊()⦉@3, + } +}@6⦊⦉@6
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..9cf86ce34a04d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,79 @@ + + + + +async.m-{closure#0} - Coverage Spans + + + +
@0,1⦊{ x - 1 }⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..04412c1d99427 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m.-------.InstrumentCoverage.0.html @@ -0,0 +1,74 @@ + + + + +async.m - Coverage Spans + + + +
@0,1⦊async fn m(x: u8) -> u8 ⦉@0,1{ x - 1 }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..611799161d398 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,190 @@ + + + + +async.main - Coverage Spans + + + +
@0,1,2,3,4,5,6,7,8,9,10,11,12,13⦊fn main() { + let _ = g(10); + let _ = h(9); + let mut future = Box::pin(i(8)); + j(7); + l(6); + let _ = m(5); + executor::block_on(future.as_mut()); +}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html similarity index 64% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html index 2d179aa0f1147..523e839a918dd 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -closure.main-{closure#2} - Coverage Spans +closure.main-{closure#10} - Coverage Spans + + +
|val| + @0⦊{ + let mut countdown = 0; + if is_false⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3@2⦊⦉@2 + @4,5,6,7,8⦊format!("'{}'", val) + }⦉@4,5,6,7,8
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..032a6a7e435c1 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html @@ -0,0 +1,93 @@ + + + + +closure.main-{closure#3} - Coverage Spans + + + +
| + mut countdown + | + @0⦊{ + if is_false⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3@2⦊⦉@2 + @4,5⦊"closure should be unused".to_owned() + }⦉@4,5
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#4}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#4}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..df0172bdf7067 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#4}.-------.InstrumentCoverage.0.html @@ -0,0 +1,77 @@ + + + + +closure.main-{closure#4} - Coverage Spans + + + +
| _unused_arg: u8 | @0,1⦊countdown += 1⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#5}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#5}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..e28038fd3fec6 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#5}.-------.InstrumentCoverage.0.html @@ -0,0 +1,115 @@ + + + + +closure.main-{closure#5} - Coverage Spans + + + +
@0,1,2⦊{ + $crate::io::_print($crate::format_args_nl!($($arg)*)); + }⦉@0,1,2
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#8}-clone.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#6}.-------.InstrumentCoverage.0.html similarity index 58% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#8}-clone.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#6}.-------.InstrumentCoverage.0.html index a61d3cb8bdcb3..d479211aa37e5 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#8}-clone.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#6}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -partial_eq.{impl#8}-clone - Coverage Spans +closure.main-{closure#6} - Coverage Spans -
@0,1,2,3⦊Clone⦉@0,1,2,3
+
| _unused_arg: u8 | @0,1,2⦊{ println!("not called") }⦉@0,1,2
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#7}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#7}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..2734c0b24688c --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#7}.-------.InstrumentCoverage.0.html @@ -0,0 +1,115 @@ + + + + +closure.main-{closure#7} - Coverage Spans + + + +
| _unused_arg: u8 | @0,1,2⦊{ + println!("not called") + }⦉@0,1,2
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#8}.-------.InstrumentCoverage.0.html similarity index 57% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#8}.-------.InstrumentCoverage.0.html index 6c4ce72305e53..a032df54ea21c 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#8}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -inner_items.main-{impl#0}-trait_func - Coverage Spans +closure.main-{closure#8} - Coverage Spans -
fn trait_func(&mut self, incr: u32) { - self.in_struct_field += @0⦊incr⦉@0; - @1,2⦊in_func(self.in_struct_field); - }⦉@1,2
+
| + _unused_arg: u8 + | @0,1,2⦊{ println!("not called") }⦉@0,1,2
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#9}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#9}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..3c174e03ebe35 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#9}.-------.InstrumentCoverage.0.html @@ -0,0 +1,89 @@ + + + + +closure.main-{closure#9} - Coverage Spans + + + +
| + _unused_arg: u8 + | @0,1,2⦊{ println!("not called") }⦉@0,1,2
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..3bd446b0e049d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,10921 @@ + + + + +closure.main - Coverage Spans + + + +
@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let is_false = ! is_true; + + let mut some_string = Some(String::from("the string content")); + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 1".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊ + ) + ); + + some_string = Some(String::from("the string content")); + let + a + = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 2".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + a + ) + ); + + some_string = None; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 3".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊ + ) + ); + + some_string = None; + let + a + = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 4".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + a + ) + ); + + let + quote_closure + = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|val| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + format!("'{}'", val) + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + println!( + "Repeated, quoted string: {:?}" + , + std::iter::repeat("repeat me") + .take(5) + .map + ( + quote_closure + ) + .collect::<Vec<_>>() + ); + + let + _unused_closure + = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| + mut countdown + | + { + if is_false { + countdown = 10; + } + "closure should be unused".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + + let mut countdown = 10; + let _short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 | countdown += 1@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + + // Macros can sometimes confuse the coverage results. Compare this next assignment, with an + // unused closure that invokes the `println!()` macro, with the closure assignment above, that + // does not use a macro. The closure above correctly shows `0` executions. + let _short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 | println!("not called")@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + // The closure assignment above is executed, with a line count of `1`, but the `println!()` + // could not have been called, and yet, there is no indication that it wasn't... + + // ...but adding block braces gives the expected result, showing the block was not executed. + let _short_unused_closure_block = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 | { println!("not called") }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + + let _shortish_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 | { + println!("not called") + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + + let _as_short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| + _unused_arg: u8 + | { println!("not called") }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + + let _almost_as_short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| + _unused_arg: u8 + | { println!("not called") }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊ + ; +}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..e16b366e2162e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,326 @@ + + + + +conditions.main - Coverage Spans + + + +
@0⦊fn main() ⦉@0{ + let @0⦊mut countdown = 0; + if true⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3@2⦊⦉@2 + + const B: u32 = 100; + let @25⦊x⦉@25 = if @4⦊countdown > 7⦉@4 { + @5,7,8⦊countdown -= 4; + B⦉@5,7,8 + } else if @6⦊countdown > 2⦉@6 { + if @9,11⦊countdown < 1⦉@9,11 || @18⦊countdown > 5⦉@18 || @14⦊countdown != 9⦉@14 @20,22⦊{ + countdown = 0; + }⦉@20,22@21⦊⦉@21 + @23,24⦊countdown -= 5; + countdown⦉@23,24 + } else { + @10⦊return⦉@10; + }; + + let @25⦊mut countdown = 0; + if true⦉@25 @26,28⦊{ + countdown = 10; + }⦉@26,28@27⦊⦉@27 + + if @29⦊countdown > 7⦉@29 @30,32,33⦊{ + countdown -= 4; + }⦉@30,32,33 else if @31⦊countdown > 2⦉@31 { + if @34,36⦊countdown < 1⦉@34,36 || @43⦊countdown > 5⦉@43 || @39⦊countdown != 9⦉@39 @45,47⦊{ + countdown = 0; + }⦉@45,47@46⦊⦉@46 + @48,49⦊countdown -= 5⦉@48,49; + } else { + @35⦊return⦉@35; + } + + if @50⦊true⦉@50 { + let @51,53⦊mut countdown = 0; + if true⦉@51,53 @54,56⦊{ + countdown = 10; + }⦉@54,56@55⦊⦉@55 + + if @57⦊countdown > 7⦉@57 @58,60,61⦊{ + countdown -= 4; + }⦉@58,60,61 + else if @59⦊countdown > 2⦉@59 { + if @62,64⦊countdown < 1⦉@62,64 || @71⦊countdown > 5⦉@71 || @67⦊countdown != 9⦉@67 @73,75⦊{ + countdown = 0; + }⦉@73,75@74⦊⦉@74 + @76,77⦊countdown -= 5⦉@76,77; + } else { + @63⦊return⦉@63; + } + }@52⦊⦉@52 // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal + // `true` was const-evaluated. The compiler knows the `if` block will be executed. + + let @79⦊mut countdown = 0; + if true⦉@79 @80,82⦊{ + countdown = 1; + }⦉@80,82@81⦊⦉@81 + + let @106⦊z⦉@106 = if @83⦊countdown > 7⦉@83 @84,86,87⦊{ + countdown -= 4; + }⦉@84,86,87 else if @85⦊countdown > 2⦉@85 { + if @88,90⦊countdown < 1⦉@88,90 || @97⦊countdown > 5⦉@97 || @93⦊countdown != 9⦉@93 @99,101⦊{ + countdown = 0; + }⦉@99,101@100⦊⦉@100 + @102,103⦊countdown -= 5⦉@102,103; + } else { + let @89,104,105⦊should_be_reachable = countdown; + println!("reached"); + return⦉@89,104,105; + }; + + let @127⦊w⦉@127 = if @106⦊countdown > 7⦉@106 @107,109,110⦊{ + countdown -= 4; + }⦉@107,109,110 else if @108⦊countdown > 2⦉@108 { + if @111,113⦊countdown < 1⦉@111,113 || @120⦊countdown > 5⦉@120 || @116⦊countdown != 9⦉@116 @122,124⦊{ + countdown = 0; + }⦉@122,124@123⦊⦉@123 + @125,126⦊countdown -= 5⦉@125,126; + } else { + @112⦊return⦉@112; + }; +}@131⦊⦉@131
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..59d00600738f0 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,151 @@ + + + + +dead_code.main - Coverage Spans + + + +
@0,1,2,3⦊fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 10; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_fn.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_fn.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..1a535b937887b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_fn.-------.InstrumentCoverage.0.html @@ -0,0 +1,151 @@ + + + + +dead_code.unused_fn - Coverage Spans + + + +
@0,1,2,3⦊fn unused_fn() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 10; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_pub_fn_not_in_library.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_pub_fn_not_in_library.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..6eff51ad89c73 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_pub_fn_not_in_library.-------.InstrumentCoverage.0.html @@ -0,0 +1,151 @@ + + + + +dead_code.unused_pub_fn_not_in_library - Coverage Spans + + + +
@0,1,2,3⦊pub fn unused_pub_fn_not_in_library() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 10; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html similarity index 64% rename from src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html index aebeb39fd5179..fa3c4b3c31257 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ + + +inner_items.main-in_func - Coverage Spans + + + +
@0,1,2,3,4⦊fn in_func(a: u32) { + let b = 1; + let c = a + b; + println!("c = {}", c) + }⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html similarity index 51% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html index 9b57c6a737817..ee1e0339049e1 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -inner_items.main-InTrait-default_trait_func - Coverage Spans +inner_items.main-{impl#0}-trait_func - Coverage Spans -
fn default_trait_func(&mut self) @0,1,2⦊{ - in_func(IN_CONST); - self.trait_func(IN_CONST); - }⦉@0,1,2
+
@0,1,2⦊fn trait_func(&mut self, incr: u32) { + self.in_struct_field += incr; + in_func(self.in_struct_field); + }⦉@0,1,2
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html similarity index 81% rename from src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html index 815d5efbce69f..693b15f15b9ca 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ + + +overflow.main - Coverage Spans + + + +
@0⦊fn main() -> Result<(),u8> { + let mut countdown = 10⦉@0; + while @1,2⦊countdown > 0⦉@1,2 { + if @3,5⦊countdown == 1⦉@3,5 @6,8,9,10,11,12⦊{ + let result = might_overflow(10); + println!("Result: {}", result); + }⦉@6,8,9,10,11,12 else if @7⦊countdown < 5⦉@7 @13,15,16,17,18,19⦊{ + let result = might_overflow(1); + println!("Result: {}", result); + }⦉@13,15,16,17,18,19@14⦊⦉@14 + @21,22⦊countdown -= 1⦉@21,22; + } + @4⦊Ok(()) +}⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..c72ad42635620 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html @@ -0,0 +1,396 @@ + + + + +overflow.might_overflow - Coverage Spans + + + +
@0⦊fn might_overflow(to_add: u32) -> u32 { + if to_add > 5⦉@0 @1,3,4,5⦊{ + println!("this will probably overflow"); + }⦉@1,3,4,5@2⦊⦉@2 + let @6,7,8,9,10,11,12,13,14⦊add_to = u32::MAX - 5; + println!("does {} + {} overflow?", add_to, to_add); + let result = to_add + add_to; + println!("continuing after overflow check"); + result +}⦉@6,7,8,9,10,11,12,13,14
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..bd6aac4103eb6 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,104 @@ + + + + +panic_unwind.main - Coverage Spans + + + +
@0⦊fn main() -> Result<(), u8> { + let mut countdown = 10⦉@0; + while @1,2⦊countdown > 0⦉@1,2 { + if @3,5⦊countdown == 1⦉@3,5 @6,8,9⦊{ + might_panic(true); + }⦉@6,8,9 else if @7⦊countdown < 5⦉@7 @10,12,13⦊{ + might_panic(false); + }⦉@10,12,13@11⦊⦉@11 + @15,16⦊countdown -= 1⦉@15,16; + } + @4⦊Ok(()) +}⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..290b7b8509908 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html @@ -0,0 +1,164 @@ + + + + +panic_unwind.might_panic - Coverage Spans + + + +
@0⦊fn might_panic(should_panic: bool) ⦉@0{ + if @0⦊should_panic⦉@0 { + @1,3,4,5⦊println!("panicking..."); + panic!("panics");⦉@1,3,4,5 + } else @2,6,7⦊{ + println!("Don't Panic"); + } +}⦉@2,6,7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html similarity index 97% rename from src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html index a7830911376bf..6d9d63deccf17 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ + + +partial_eq.{impl#1}-cmp - Coverage Spans + + + +
@0,1⦊⦉@0,1Ord@15⦊⦉@15
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html similarity index 89% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html index 0fa59ade1398d..47f9ab2bd5e7d 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ + + +partial_eq.{impl#2}-partial_cmp - Coverage Spans + + + +
@0,1⦊⦉@0,1PartialOrd@18⦊⦉@18
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html similarity index 87% rename from src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html index b908a35f1b799..ebb8b1c15ce08 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -partial_eq.{impl#6}-eq - Coverage Spans +partial_eq.{impl#6}-ne - Coverage Spans -
@2⦊@1⦊PartialEq⦉@1⦉@2@4⦊⦉@4
+
@0⦊⦉@0PartialEq@4⦊⦉@4
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html similarity index 96% rename from src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html index 65b95bae78d6e..195ef4da7b484 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ + + +simple_loop.main - Coverage Spans + + + +
@0,1,2,3⦊fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + + if + is_true⦉@0,1,2,3 + @4,6⦊{ + countdown + = + 10 + ; + }⦉@4,6@5⦊⦉@5 + + loop + { + if + @8,9⦊countdown + == + 0⦉@8,9 + { + @10,12⦊break⦉@10,12 + ; + }@11,13⦊ + countdown + -= + 1⦉@11,13 + ; + } +}@10,12⦊⦉@10,12
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html similarity index 63% rename from src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html index 2488ac563e77e..a8bae32490b0b 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ + + +used_crate.unused_function - Coverage Spans + + + +
@0,1,2,3⦊pub fn unused_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 20; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..6b0ce85c4606f --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +used_crate.unused_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn unused_generic_function<T: Debug>(arg: T) { + println!("unused_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_private_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_private_function.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..361c57930229a --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_private_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,119 @@ + + + + +used_crate.unused_private_function - Coverage Spans + + + +
@0,1,2,3⦊fn unused_private_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 20; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..7c44c536379d2 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html @@ -0,0 +1,190 @@ + + + + +used_crate.use_this_lib_crate - Coverage Spans + + + +
@0,1,2,3,4,5,6,7⦊fn use_this_lib_crate() { + used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + "used from library used_crate.rs", + ); + let some_vec = vec![5, 6, 7, 8]; + used_only_from_this_lib_crate_generic_function(some_vec); + used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); +}⦉@0,1,2,3,4,5,6,7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..8b994a6962b83 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +used_crate.used_from_bin_crate_and_lib_crate_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) { + println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_function.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..2ffd9bfb82386 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,113 @@ + + + + +used_crate.used_function - Coverage Spans + + + +
@0,1,2,3⦊pub fn used_function() ⦉@0,1,2,3{ + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + let mut countdown = 0; + if is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 10; + }⦉@4,6@5⦊⦉@5 + @7,8⦊use_this_lib_crate(); +}⦉@7,8
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_bin_crate_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_bin_crate_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..29fe03382c7f0 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_bin_crate_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +used_crate.used_only_from_bin_crate_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { + println!("used_only_from_bin_crate_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_this_lib_crate_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_this_lib_crate_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..76bc057dd00a9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_this_lib_crate_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +used_crate.used_only_from_this_lib_crate_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { + println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_with_same_type_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_with_same_type_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..a2f4b7e19ebdd --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_with_same_type_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +used_crate.used_with_same_type_from_bin_crate_and_lib_crate_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) { + println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..ba6af60fa5cc9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,193 @@ + + + + +uses_crate.main - Coverage Spans + + + +
@0,1,2,3,4,5,6,7,8⦊fn main() { + used_crate::used_function(); + let some_vec = vec![1, 2, 3, 4]; + used_crate::used_only_from_bin_crate_generic_function(&some_vec); + used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); + used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); + used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); +}⦉@0,1,2,3,4,5,6,7,8
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html similarity index 85% rename from src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html index 3ba5135122b93..f037a8ee5c52f 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -partial_eq.{impl#2}-le-{closure#0} - Coverage Spans +yield.main-{closure#0} - Coverage Spans -
major: usize, - @0,1,2,3⦊⦉@0,1,2,3minor: usize
+
|| @0⦊{ + yield 1⦉@0; + return @1⦊"foo" + }⦉@1
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..842d7823bfd12 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html @@ -0,0 +1,81 @@ + + + + +yield.main-{closure#1} - Coverage Spans + + + +
|| @0⦊{ + yield 1⦉@0; + @1⦊yield 2⦉@1; + @2⦊yield 3⦉@2; + return @3⦊"foo" + }⦉@3
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..99e56393ea599 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,138 @@ + + + + +yield.main - Coverage Spans + + + +
@0,1,2⦊fn main() ⦉@0,1,2{ + let @0,1,2⦊mut generator⦉@0,1,2 = || { + yield 1; + return "foo" + }; + + match @0,1,2⦊Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1)⦉@0,1,2 => @4,6,7,8⦊{}⦉@4,6,7,8 + _ => @5⦊panic!("unexpected value from resume")⦉@5, + } + match @4,6,7,8⦊Pin::new(&mut generator).resume(())⦉@4,6,7,8 { + GeneratorState::Complete(@10,11⦊"foo"⦉@10,11) => @12,13,14,15⦊{}⦉@12,13,14,15 + _ => @9⦊panic!("unexpected value from resume")⦉@9, + } + + let @12,13,14,15⦊mut generator⦉@12,13,14,15 = || { + yield 1; + yield 2; + yield 3; + return "foo" + }; + + match @12,13,14,15⦊Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1)⦉@12,13,14,15 => @17,19,20,21⦊{}⦉@17,19,20,21 + _ => @18⦊panic!("unexpected value from resume")⦉@18, + } + match @17,19,20,21⦊Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(2)⦉@17,19,20,21 => @23,25⦊{}⦉@23,25 + _ => @24⦊panic!("unexpected value from resume")⦉@24, + } +}@23,25⦊⦉@23,25
+ + diff --git a/src/test/run-make-fulldeps/coverage/abort.rs b/src/test/run-make-fulldeps/coverage/abort.rs new file mode 100644 index 0000000000000..52c6ff333e4ea --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/abort.rs @@ -0,0 +1,67 @@ +#![feature(unwind_attributes)] +#![allow(unused_assignments)] + +#[unwind(aborts)] +fn might_abort(should_abort: bool) { + if should_abort { + println!("aborting..."); + panic!("panics and aborts"); + } else { + println!("Don't Panic"); + } +} + +fn main() -> Result<(), u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown < 5 { + might_abort(false); + } + // See discussion (below the `Notes` section) on coverage results for the closing brace. + if countdown < 5 { might_abort(false); } // Counts for different regions on one line. + // For the following example, the closing brace is the last character on the line. + // This shows the character after the closing brace is highlighted, even if that next + // character is a newline. + if countdown < 5 { might_abort(false); } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the similar tests +// `panic_unwind.rs` and `try_error_result.rs`. +// 2. This test confirms the coverage generated when a program includes `TerminatorKind::Abort`. +// 3. The test does not invoke the abort. By executing to a successful completion, the coverage +// results show where the program did and did not execute. +// 4. If the program actually aborted, the coverage counters would not be saved (which "works as +// intended"). Coverage results would show no executed coverage regions. +// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status +// (on Linux at least). + +/* + +Expect the following coverage results: + +```text + 16| 11| while countdown > 0 { + 17| 10| if countdown < 5 { + 18| 4| might_abort(false); + 19| 6| } +``` + +This is actually correct. + +The condition `countdown < 5` executed 10 times (10 loop iterations). + +It evaluated to `true` 4 times, and executed the `might_abort()` call. + +It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit +`else`, the coverage implementation injects a counter, at the character immediately after the `if`s +closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the +non-true condition. + +As another example of why this is important, say the condition was `countdown < 50`, which is always +`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called. +The closing brace would have a count of `0`, highlighting the missed coverage. +*/ diff --git a/src/test/run-make-fulldeps/coverage/assert.rs b/src/test/run-make-fulldeps/coverage/assert.rs new file mode 100644 index 0000000000000..c85f2748eb9d8 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/assert.rs @@ -0,0 +1,32 @@ +#![allow(unused_assignments)] +// expect-exit-status-101 + +fn might_fail_assert(one_plus_one: u32) { + println!("does 1 + 1 = {}?", one_plus_one); + assert_eq!(1 + 1, one_plus_one, "the argument was wrong"); +} + +fn main() -> Result<(),u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown == 1 { + might_fail_assert(3); + } else if countdown < 5 { + might_fail_assert(2); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the very similar test +// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`. +// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or +// related `assert_*!()` macro. +// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce +// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to +// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). +// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test +// (and in many other coverage tests). The `Assert` terminator is typically generated by the +// Rust compiler to check for runtime failures, such as numeric overflows. diff --git a/src/test/run-make-fulldeps/coverage/async.rs b/src/test/run-make-fulldeps/coverage/async.rs new file mode 100644 index 0000000000000..5553af92465ca --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/async.rs @@ -0,0 +1,128 @@ +#![allow(unused_assignments, dead_code)] + +// require-rust-edition-2018 + +async fn c(x: u8) -> u8 { + if x == 8 { + 1 + } else { + 0 + } +} + +async fn d() -> u8 { 1 } + +async fn e() -> u8 { 1 } // unused function; executor does not block on `g()` + +async fn f() -> u8 { 1 } + +async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` + +pub async fn g(x: u8) { + match x { + y if e().await == y => (), + y if f().await == y => (), + _ => (), + } +} + +async fn h(x: usize) { // The function signature is counted when called, but the body is not + // executed (not awaited) so the open brace has a `0` count (at least when + // displayed with `llvm-cov show` in color-mode). + match x { + y if foo().await[y] => (), + _ => (), + } +} + +async fn i(x: u8) { // line coverage is 1, but there are 2 regions: + // (a) the function signature, counted when the function is called; and + // (b) the open brace for the function body, counted once when the body is + // executed asynchronously. + match x { + y if c(x).await == y + 1 => { d().await; } + y if f().await == y + 1 => (), + _ => (), + } +} + +fn j(x: u8) { + // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`. + fn c(x: u8) -> u8 { + if x == 8 { + 1 // This line appears covered, but the 1-character expression span covering the `1` + // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because + // `fn j()` executes the open brace for the funciton body, followed by the function's + // first executable statement, `match x`. Inner function declarations are not + // "visible" to the MIR for `j()`, so the code region counts all lines between the + // open brace and the first statement as executed, which is, in a sense, true. + // `llvm-cov show` overcomes this kind of situation by showing the actual counts + // of the enclosed coverages, (that is, the `1` expression was not executed, and + // accurately displays a `0`). + } else { + 0 + } + } + fn d() -> u8 { 1 } + fn f() -> u8 { 1 } + match x { + y if c(x) == y + 1 => { d(); } + y if f() == y + 1 => (), + _ => (), + } +} + +fn k(x: u8) { // unused function + match x { + 1 => (), + 2 => (), + _ => (), + } +} + +fn l(x: u8) { + match x { + 1 => (), + 2 => (), + _ => (), + } +} + +async fn m(x: u8) -> u8 { x - 1 } + +fn main() { + let _ = g(10); + let _ = h(9); + let mut future = Box::pin(i(8)); + j(7); + l(6); + let _ = m(5); + executor::block_on(future.as_mut()); +} + +mod executor { + use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + pub fn block_on(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unimplemented!("clone"), + |_| unimplemented!("wake"), + |_| unimplemented!("wake_by_ref"), + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +} diff --git a/src/test/run-make-fulldeps/coverage/closure.rs b/src/test/run-make-fulldeps/coverage/closure.rs index 66bbbc55399fe..914cb0fe051c7 100644 --- a/src/test/run-make-fulldeps/coverage/closure.rs +++ b/src/test/run-make-fulldeps/coverage/closure.rs @@ -90,4 +90,66 @@ fn main() { a ) ); + + let + quote_closure + = + |val| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + format!("'{}'", val) + }; + println!( + "Repeated, quoted string: {:?}" + , + std::iter::repeat("repeat me") + .take(5) + .map + ( + quote_closure + ) + .collect::>() + ); + + let + _unused_closure + = + | + mut countdown + | + { + if is_false { + countdown = 10; + } + "closure should be unused".to_owned() + }; + + let mut countdown = 10; + let _short_unused_closure = | _unused_arg: u8 | countdown += 1; + + // Macros can sometimes confuse the coverage results. Compare this next assignment, with an + // unused closure that invokes the `println!()` macro, with the closure assignment above, that + // does not use a macro. The closure above correctly shows `0` executions. + let _short_unused_closure = | _unused_arg: u8 | println!("not called"); + // The closure assignment above is executed, with a line count of `1`, but the `println!()` + // could not have been called, and yet, there is no indication that it wasn't... + + // ...but adding block braces gives the expected result, showing the block was not executed. + let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; + + let _shortish_unused_closure = | _unused_arg: u8 | { + println!("not called") + }; + + let _as_short_unused_closure = | + _unused_arg: u8 + | { println!("not called") }; + + let _almost_as_short_unused_closure = | + _unused_arg: u8 + | { println!("not called") } + ; } diff --git a/src/test/run-make-fulldeps/coverage/conditions.rs b/src/test/run-make-fulldeps/coverage/conditions.rs index da206e28f31da..8a2a0b53e5862 100644 --- a/src/test/run-make-fulldeps/coverage/conditions.rs +++ b/src/test/run-make-fulldeps/coverage/conditions.rs @@ -36,6 +36,26 @@ fn main() { return; } + if true { + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } + else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } + } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal + // `true` was const-evaluated. The compiler knows the `if` block will be executed. + let mut countdown = 0; if true { countdown = 1; diff --git a/src/test/run-make-fulldeps/coverage/coverage_tools.mk b/src/test/run-make-fulldeps/coverage/coverage_tools.mk index 99a2e0ba9523e..7dc485cd94d66 100644 --- a/src/test/run-make-fulldeps/coverage/coverage_tools.mk +++ b/src/test/run-make-fulldeps/coverage/coverage_tools.mk @@ -2,39 +2,16 @@ # file with the line: # # -include ../instrument-coverage/coverage_tools.mk -# -# To enable the Rust compiler option `-C link-dead-code`, also set the following variable -# *BEFORE* the `-include` line: -# -# LINK_DEAD_CODE=yes -include ../tools.mk -ifndef LINK_DEAD_CODE - LINK_DEAD_CODE=no -endif - # ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and # `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw` # file, required for coverage reports. # -# Enabling `-C link-dead-code` is preferred when compiling with `-Z instrument-coverage`, so -# `-C link-dead-code` is automatically enabled for all platform targets _except_ MSVC. -# -# Making the state of `-C link-dead-code` platform-dependent creates a problem for cross-platform -# tests because the injected counters, coverage reports, and some low-level output can be different, -# depending on the `-C link-dead-code` setting. For example, coverage reports will not report any -# coverage for a dead code region when the `-C link-dead-code` option is disabled, but with the -# option enabled, those same regions will show coverage counter values (of zero, of course). -# -# To ensure cross-platform `-Z instrument-coverage` generate consistent output, the -# `-C link-dead-code` option is always explicitly enabled or disabled. -# -# Since tests that execute binaries enabled with both `-Z instrument-coverage` and -# `-C link-dead-code` are known to fail, those tests will need the `# ignore-msvc` setting. -# -# If and when the above issue is resolved, the `# ignore-msvc` option can be removed, and the -# tests can be simplified to always test with `-C link-dead-code`. +# Enabling `-C link-dead-code` is not necessary when compiling with `-Z instrument-coverage`, +# due to improvements in the coverage map generation, to add unreachable functions known to Rust. +# Therefore, `-C link-dead-code` is no longer automatically enabled. UNAME = $(shell uname) @@ -44,8 +21,3 @@ LLVM_VERSION_11_PLUS := $(shell \ LLVM_VERSION=$$("$(LLVM_BIN_DIR)"/llvm-config --version) && \ LLVM_VERSION_MAJOR=$${LLVM_VERSION/.*/} && \ [ $$LLVM_VERSION_MAJOR -ge 11 ] && echo true || echo false) - -# FIXME(richkadel): Can any of the features tested by `run-make-fulldeps/coverage-*` tests be tested -# just as completely by more focused unit tests of the code logic itself, to reduce the number of -# test result files generated and maintained, and to help identify specific test failures and root -# causes more easily? diff --git a/src/test/run-make-fulldeps/coverage/dead_code.rs b/src/test/run-make-fulldeps/coverage/dead_code.rs new file mode 100644 index 0000000000000..a1285df0ec62a --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/dead_code.rs @@ -0,0 +1,37 @@ +#![allow(unused_assignments, unused_variables)] + +pub fn unused_pub_fn_not_in_library() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } +} + +fn unused_fn() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } +} + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } +} diff --git a/src/test/run-make-fulldeps/coverage/generics.rs b/src/test/run-make-fulldeps/coverage/generics.rs index f4e6402694480..cbeda35d3b8cf 100644 --- a/src/test/run-make-fulldeps/coverage/generics.rs +++ b/src/test/run-make-fulldeps/coverage/generics.rs @@ -30,7 +30,11 @@ fn main() -> Result<(),u8> { if true { println!("Exiting with error..."); return Err(1); - } + } // The remaining lines below have no coverage because `if true` (with the constant literal + // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`. + // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown + // in other tests, the lines below would have coverage (which would show they had `0` + // executions, assuming the condition still evaluated to `true`). let _ = Firework { strength: 1000 }; diff --git a/src/test/run-make-fulldeps/coverage/if_else.rs b/src/test/run-make-fulldeps/coverage/if_else.rs index 3ae4b7a7316bd..3244e1e3afd2b 100644 --- a/src/test/run-make-fulldeps/coverage/if_else.rs +++ b/src/test/run-make-fulldeps/coverage/if_else.rs @@ -1,4 +1,4 @@ -#![allow(unused_assignments)] +#![allow(unused_assignments, unused_variables)] fn main() { // Initialize test constants in a way that cannot be determined at compile time, to ensure diff --git a/src/test/run-make-fulldeps/coverage/inner_items.rs b/src/test/run-make-fulldeps/coverage/inner_items.rs index 66e76513e2692..bcb62b3031cd9 100644 --- a/src/test/run-make-fulldeps/coverage/inner_items.rs +++ b/src/test/run-make-fulldeps/coverage/inner_items.rs @@ -1,4 +1,4 @@ -#![allow(unused_assignments, unused_variables)] +#![allow(unused_assignments, unused_variables, dead_code)] fn main() { // Initialize test constants in a way that cannot be determined at compile time, to ensure diff --git a/src/test/run-make-fulldeps/coverage/lib/used_crate.rs b/src/test/run-make-fulldeps/coverage/lib/used_crate.rs new file mode 100644 index 0000000000000..e5555f9193576 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/lib/used_crate.rs @@ -0,0 +1,104 @@ +#![allow(unused_assignments, unused_variables)] + +use std::fmt::Debug; + +pub fn used_function() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let mut countdown = 0; + if is_true { + countdown = 10; + } + use_this_lib_crate(); +} + +pub fn used_only_from_bin_crate_generic_function(arg: T) { + println!("used_only_from_bin_crate_generic_function with {:?}", arg); +} + +pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); +} + +pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); +} + +pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); +} + +pub fn unused_generic_function(arg: T) { + println!("unused_generic_function with {:?}", arg); +} + +pub fn unused_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true { + countdown = 20; + } +} + +fn unused_private_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true { + countdown = 20; + } +} + +fn use_this_lib_crate() { + used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + "used from library used_crate.rs", + ); + let some_vec = vec![5, 6, 7, 8]; + used_only_from_this_lib_crate_generic_function(some_vec); + used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); +} + +// FIXME(#79651): `used_from_bin_crate_and_lib_crate_generic_function()` is covered and executed +// `2` times, but the coverage output also shows (at the bottom of the coverage report): +// ------------------ +// | Unexecuted instantiation: +// ------------------ +// +// Note, the function name shown in the error seems to change depending on the structure of the +// code, for some reason, including: +// +// * used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str> +// * used_crate::use_this_lib_crate +// +// The `Unexecuted instantiation` error may be related to more than one generic function. Since the +// reporting is not consistent, it may not be obvious if there are multiple problems here; however, +// `used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>` (which I have seen +// with this error) is the only generic function missing instantiaion coverage counts. +// +// The `&str` variant was called from within this `lib` crate, and the `bin` crate also calls this +// function, but with `T` type `&Vec`. +// +// I believe the reason is that one or both crates are generating `Zero` counters for what it +// believes are "Unreachable" instantiations, but those instantiations are counted from the +// coverage map in the other crate. +// +// See `add_unreachable_coverage()` in `mapgen.rs` for more on how these `Zero` counters are added +// for what the funciton believes are `DefId`s that did not get codegenned. I suspect the issue +// may be related to this process, but this needs to be confirmed. It may not be possible to know +// for sure if a function is truly unused and should be reported with `Zero` coverage if it may +// still get used from an external crate. (Something to look at: If the `DefId` in MIR corresponds +// _only_ to the generic function without type parameters, is the `DefId` in the codegenned set, +// instantiated with one of the type parameters (in either or both crates) a *different* `DefId`? +// If so, `add_unreachable_coverage()` would assume the MIR `DefId` was uncovered, and would add +// unreachable coverage. +// +// I didn't think they could be different, but if they can, we would need to find the `DefId` for +// the generic function MIR and include it in the set of "codegenned" DefIds if any instantiation +// of that generic function does exist. +// +// Note, however, for `used_with_same_type_from_bin_crate_and_lib_crate_generic_function()` both +// crates use this function with the same type variant. The function does not have multiple +// instantiations, so the coverage analysis is not confused. No "Unexecuted instantiations" errors +// are reported. diff --git a/src/test/run-make-fulldeps/coverage/loop_break_value.rs b/src/test/run-make-fulldeps/coverage/loop_break_value.rs index ba66d136de1e3..dbc4fad7a2316 100644 --- a/src/test/run-make-fulldeps/coverage/loop_break_value.rs +++ b/src/test/run-make-fulldeps/coverage/loop_break_value.rs @@ -1,4 +1,4 @@ -#![allow(unused_assignments)] +#![allow(unused_assignments, unused_variables)] fn main() { let result diff --git a/src/test/run-make-fulldeps/coverage/loops_branches.rs b/src/test/run-make-fulldeps/coverage/loops_branches.rs index a9df7e0fab75f..938421d32e7a5 100644 --- a/src/test/run-make-fulldeps/coverage/loops_branches.rs +++ b/src/test/run-make-fulldeps/coverage/loops_branches.rs @@ -1,4 +1,4 @@ -#![allow(unused_assignments)] +#![allow(unused_assignments, unused_variables, while_true)] // This test confirms an earlier problem was resolved, supporting the MIR graph generated by the // structure of this `fmt` function. diff --git a/src/test/run-make-fulldeps/coverage/overflow.rs b/src/test/run-make-fulldeps/coverage/overflow.rs new file mode 100644 index 0000000000000..e537b0e95c32a --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/overflow.rs @@ -0,0 +1,63 @@ +#![allow(unused_assignments)] +// expect-exit-status-101 + +fn might_overflow(to_add: u32) -> u32 { + if to_add > 5 { + println!("this will probably overflow"); + } + let add_to = u32::MAX - 5; + println!("does {} + {} overflow?", add_to, to_add); + let result = to_add + add_to; + println!("continuing after overflow check"); + result +} + +fn main() -> Result<(),u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown == 1 { + let result = might_overflow(10); + println!("Result: {}", result); + } else if countdown < 5 { + let result = might_overflow(1); + println!("Result: {}", result); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`, +// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`. +// 2. This test confirms the coverage generated when a program passes or fails a +// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case). +// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`, +// compiler-generated assertion failures are assumed to be a symptom of a program bug, not +// expected behavior. To simplify the coverage graphs and keep instrumented programs as +// small and fast as possible, `Assert` terminators are assumed to always succeed, and +// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not +// get its own coverage counter. +// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive. +// In this test, the final count for the statements after the `if` block in `might_overflow()` +// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending +// on the MIR graph and the structure of the code, this count could have been 3 (which might +// have been valid for the overflowed add `+`, but should have been 4 for the lines before +// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented +// via StatementKind::Counter at the end of the block, but (as in the case in this test), +// a CounterKind::Expression is always evaluated. In this case, the expression was based on +// a `Counter` incremented as part of the evaluation of the `if` expression, which was +// executed, and counted, 4 times, before reaching the overflow add. + +// If the program did not overflow, the coverage for `might_overflow()` would look like this: +// +// 4| |fn might_overflow(to_add: u32) -> u32 { +// 5| 4| if to_add > 5 { +// 6| 0| println!("this will probably overflow"); +// 7| 4| } +// 8| 4| let add_to = u32::MAX - 5; +// 9| 4| println!("does {} + {} overflow?", add_to, to_add); +// 10| 4| let result = to_add + add_to; +// 11| 4| println!("continuing after overflow check"); +// 12| 4| result +// 13| 4|} diff --git a/src/test/run-make-fulldeps/coverage/panic_unwind.rs b/src/test/run-make-fulldeps/coverage/panic_unwind.rs new file mode 100644 index 0000000000000..b6c0c080762b2 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/panic_unwind.rs @@ -0,0 +1,49 @@ +#![allow(unused_assignments)] +// expect-exit-status-101 + +fn might_panic(should_panic: bool) { + if should_panic { + println!("panicking..."); + panic!("panics"); + } else { + println!("Don't Panic"); + } +} + +fn main() -> Result<(), u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown == 1 { + might_panic(true); + } else if countdown < 5 { + might_panic(false); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and +// `try_error_result.rs`. +// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the +// normal program exit cleanup, including writing out the current values of the coverage +// counters. +// 3. The coverage results show (interestingly) that the `panic!()` call did execute, but it does +// not show coverage of the `if countdown == 1` branch in `main()` that calls +// `might_panic(true)` (causing the call to `panic!()`). +// 4. The reason `main()`s `if countdown == 1` branch, calling `might_panic(true)`, appears +// "uncovered" is, InstrumentCoverage (intentionally) treats `TerminatorKind::Call` terminators +// as non-branching, because when a program executes normally, they always are. Errors handled +// via the try `?` operator produce error handling branches that *are* treated as branches in +// coverage results. By treating calls without try `?` operators as non-branching (assumed to +// return normally and continue) the coverage graph can be simplified, producing smaller, +// faster binaries, and cleaner coverage results. +// 5. The reason the coverage results actually show `panic!()` was called is most likely because +// `panic!()` is a macro, not a simple function call, and there are other `Statement`s and/or +// `Terminator`s that execute with a coverage counter before the panic and unwind occur. +// 6. Since the common practice is not to use `panic!()` for error handling, the coverage +// implementation avoids incurring an additional cost (in program size and execution time) to +// improve coverage results for an event that is generally not "supposed" to happen. +// 7. FIXME(#78544): This issue describes a feature request for a proposed option to enable +// more accurate coverage results for tests that intentionally panic. diff --git a/src/test/run-make-fulldeps/coverage/partial_eq.rs b/src/test/run-make-fulldeps/coverage/partial_eq.rs index 334fb3364ccc4..7d265ba66a445 100644 --- a/src/test/run-make-fulldeps/coverage/partial_eq.rs +++ b/src/test/run-make-fulldeps/coverage/partial_eq.rs @@ -4,8 +4,8 @@ #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Version { major: usize, - minor: usize, - patch: usize, + minor: usize, // Count: 1 - `PartialOrd` compared `minor` values in 3.2.1 vs. 3.3.0 + patch: usize, // Count: 0 - `PartialOrd` was determined by `minor` (2 < 3) } impl Version { @@ -45,55 +45,17 @@ one expression, which is allowed, but the `function_source_hash` was only passed */ -// FIXME(richkadel): It may be worth investigating why the coverage report for this test produces -// the following results: - -/* - -1. Why are their two counts below different characters (first and last) of `PartialOrd`, on line 17? - -2. Line 17 is counted twice, but the `::lt` instance shows a line count of 1? Is there a missing - line count with a different instance? Or was it really only called once? - -3. Line 20 shows another line count (of 1) for a line within a `struct` declaration (on only one of - its 3 fields). I doubt the specific field (`minor`) is relevant, but rather I suspect there's a - problem computing the file position here, for some reason. - - - 16| | - 17| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] - ^1 ^1 ------------------- -|Unexecuted instantiation: ::gt ------------------- -|Unexecuted instantiation: ::le ------------------- -|Unexecuted instantiation: ::ge ------------------- -|::lt: -| 17| 1|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] ------------------- - 18| |pub struct Version { - 19| | major: usize, - 20| 1| minor: usize, - 21| | patch: usize, - 22| |} - 23| | - 24| |impl Version { - 25| | pub fn new(major: usize, minor: usize, patch: usize) -> Self { - 26| 2| Version { - 27| 2| major, - 28| 2| minor, - 29| 2| patch, - 30| 2| } - 31| 2| } - 32| |} - 33| | - 34| 1|fn main() { - 35| 1| let version_3_2_1 = Version::new(3, 2, 1); - 36| 1| let version_3_3_0 = Version::new(3, 3, 0); - 37| 1| - 38| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version -_3_3_0); - 39| 1|} -*/ +// FIXME(#79626): The derived traits get coverage, which is great, but some of the traits appear +// to get two coverage execution counts at different positions: +// +// ```text +// 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +// ^0 ^0 ^0 ^0 ^1 ^0 ^0^0 +// ```text +// +// `PartialEq`, `PartialOrd`, and `Ord` (and possibly `Eq`, if the trait name was longer than 2 +// characters) have counts at their first and last characters. +// +// Why is this? Why does `PartialOrd` have two values (1 and 0)? This must mean we are checking +// distinct coverages, so maybe we don't want to eliminate one of them. Should we merge them? +// If merged, do we lose some information? diff --git a/src/test/run-make-fulldeps/coverage/simple_match.rs b/src/test/run-make-fulldeps/coverage/simple_match.rs index c9a24f7a9d35d..be99e59a82685 100644 --- a/src/test/run-make-fulldeps/coverage/simple_match.rs +++ b/src/test/run-make-fulldeps/coverage/simple_match.rs @@ -1,4 +1,4 @@ -#![allow(unused_assignments)] +#![allow(unused_assignments, unused_variables)] fn main() { // Initialize test constants in a way that cannot be determined at compile time, to ensure diff --git a/src/test/run-make-fulldeps/coverage/uses_crate.rs b/src/test/run-make-fulldeps/coverage/uses_crate.rs new file mode 100644 index 0000000000000..8d24b1ca3e67b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/uses_crate.rs @@ -0,0 +1,12 @@ +#![allow(unused_assignments, unused_variables)] + +extern crate used_crate; + +fn main() { + used_crate::used_function(); + let some_vec = vec![1, 2, 3, 4]; + used_crate::used_only_from_bin_crate_generic_function(&some_vec); + used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); + used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); + used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); +} diff --git a/src/test/run-make-fulldeps/coverage/while_early_ret.rs b/src/test/run-make-fulldeps/coverage/while_early_ret.rs index 14ba36238d62f..1fcea9c85c44a 100644 --- a/src/test/run-make-fulldeps/coverage/while_early_ret.rs +++ b/src/test/run-make-fulldeps/coverage/while_early_ret.rs @@ -40,8 +40,3 @@ fn main() -> Result<(),u8> { // and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program // without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical // to the coverage test for early returns, but this is a limitation that should be fixed. -// -// FIXME(richkadel): Consider creating a new tests for coverage when calling `std::process::exit()`, -// move the `ISSUE` comment to that test, and implement a new test directive that supports skipping -// coverage tests when targeting specific platforms (at least skipping Windows, or MSVC if the -// problem exists on MSVC only). diff --git a/src/test/run-make-fulldeps/coverage/yield.rs b/src/test/run-make-fulldeps/coverage/yield.rs new file mode 100644 index 0000000000000..ff7616656ff50 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/yield.rs @@ -0,0 +1,37 @@ +#![feature(generators, generator_trait)] +#![allow(unused_assignments)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; + +fn main() { + let mut generator = || { + yield 1; + return "foo" + }; + + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1) => {} + _ => panic!("unexpected value from resume"), + } + match Pin::new(&mut generator).resume(()) { + GeneratorState::Complete("foo") => {} + _ => panic!("unexpected value from resume"), + } + + let mut generator = || { + yield 1; + yield 2; + yield 3; + return "foo" + }; + + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1) => {} + _ => panic!("unexpected value from resume"), + } + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(2) => {} + _ => panic!("unexpected value from resume"), + } +} diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index 2636423c1a480..fdd7e8b24c521 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -56,7 +56,6 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { file_loader: None, diagnostic_output: DiagnosticOutput::Default, stderr: None, - crate_name: None, lint_caps: Default::default(), register_lints: None, override_queries: None, diff --git a/src/test/rustdoc-js/basic.rs b/src/test/rustdoc-js/basic.rs index 1b4963fcebea8..da946a58b1c88 100644 --- a/src/test/rustdoc-js/basic.rs +++ b/src/test/rustdoc-js/basic.rs @@ -1,2 +1,2 @@ -/// Foo +/// Docs for Foo pub struct Foo; diff --git a/src/test/rustdoc-js/summaries.js b/src/test/rustdoc-js/summaries.js new file mode 100644 index 0000000000000..f175e47342df6 --- /dev/null +++ b/src/test/rustdoc-js/summaries.js @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +const QUERY = ['summaries', 'summaries::Sidebar', 'summaries::Sidebar2']; + +const EXPECTED = [ + { + 'others': [ + { 'path': '', 'name': 'summaries', 'desc': 'This summary has a link and code.' }, + ], + }, + { + 'others': [ + { 'path': 'summaries', 'name': 'Sidebar', 'desc': 'This code will be rendered in a code tag.' }, + ], + }, + { + 'others': [ + { 'path': 'summaries', 'name': 'Sidebar2', 'desc': '' }, + ], + }, +]; diff --git a/src/test/rustdoc-js/summaries.rs b/src/test/rustdoc-js/summaries.rs new file mode 100644 index 0000000000000..beb91e286b610 --- /dev/null +++ b/src/test/rustdoc-js/summaries.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] +#![crate_name = "summaries"] + +//! This *summary* has a [link] and `code`. +//! +//! This is the second paragraph. +//! +//! [link]: https://example.com + +/// This `code` will be rendered in a code tag. +/// +/// This text should not be rendered. +pub struct Sidebar; + +/// ```text +/// this block should not be rendered +/// ``` +pub struct Sidebar2; diff --git a/src/test/rustdoc-json/check_missing_items.py b/src/test/rustdoc-json/check_missing_items.py new file mode 100644 index 0000000000000..3a3bf7fa3ed58 --- /dev/null +++ b/src/test/rustdoc-json/check_missing_items.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python + +# This test ensures that every ID in the produced json actually resolves to an item either in +# `index` or `paths`. It DOES NOT check that the structure of the produced json is actually in +# any way correct, for example an empty map would pass. + +import sys +import json + +crate = json.load(open(sys.argv[1])) + + +def get_local_item(item_id): + if item_id in crate["index"]: + return crate["index"][item_id] + print("Missing local ID:", item_id) + sys.exit(1) + + +# local IDs have to be in `index`, external ones can sometimes be in `index` but otherwise have +# to be in `paths` +def valid_id(item_id): + return item_id in crate["index"] or item_id[0] != "0" and item_id in crate["paths"] + + +def check_generics(generics): + for param in generics["params"]: + check_generic_param(param) + for where_predicate in generics["where_predicates"]: + if "bound_predicate" in where_predicate: + pred = where_predicate["bound_predicate"] + check_type(pred["ty"]) + for bound in pred["bounds"]: + check_generic_bound(bound) + elif "region_predicate" in where_predicate: + pred = where_predicate["region_predicate"] + for bound in pred["bounds"]: + check_generic_bound(bound) + elif "eq_predicate" in where_predicate: + pred = where_predicate["eq_predicate"] + check_type(pred["rhs"]) + check_type(pred["lhs"]) + + +def check_generic_param(param): + if "type" in param["kind"]: + ty = param["kind"]["type"] + if ty["default"]: + check_type(ty["default"]) + for bound in ty["bounds"]: + check_generic_bound(bound) + elif "const" in param["kind"]: + check_type(param["kind"]["const"]) + + +def check_generic_bound(bound): + if "trait_bound" in bound: + for param in bound["trait_bound"]["generic_params"]: + check_generic_param(param) + check_type(bound["trait_bound"]["trait"]) + + +def check_decl(decl): + for (_name, ty) in decl["inputs"]: + check_type(ty) + if decl["output"]: + check_type(decl["output"]) + + +def check_type(ty): + if ty["kind"] == "resolved_path": + for bound in ty["inner"]["param_names"]: + check_generic_bound(bound) + args = ty["inner"]["args"] + if args: + if "angle_bracketed" in args: + for arg in args["angle_bracketed"]["args"]: + if "type" in arg: + check_type(arg["type"]) + elif "const" in arg: + check_type(arg["const"]["type"]) + for binding in args["angle_bracketed"]["bindings"]: + if "equality" in binding["binding"]: + check_type(binding["binding"]["equality"]) + elif "constraint" in binding["binding"]: + for bound in binding["binding"]["constraint"]: + check_generic_bound(bound) + elif "parenthesized" in args: + for ty in args["parenthesized"]["inputs"]: + check_type(ty) + if args["parenthesized"]["output"]: + check_type(args["parenthesized"]["output"]) + if not valid_id(ty["inner"]["id"]): + print("Type contained an invalid ID:", ty["inner"]["id"]) + sys.exit(1) + elif ty["kind"] == "tuple": + for ty in ty["inner"]: + check_type(ty) + elif ty["kind"] == "slice": + check_type(ty["inner"]) + elif ty["kind"] == "impl_trait": + for bound in ty["inner"]: + check_generic_bound(bound) + elif ty["kind"] in ("raw_pointer", "borrowed_ref", "array"): + check_type(ty["inner"]["type"]) + elif ty["kind"] == "function_pointer": + for param in ty["inner"]["generic_params"]: + check_generic_param(param) + check_decl(ty["inner"]["inner"]) + elif ty["kind"] == "qualified_path": + check_type(ty["inner"]["self_type"]) + check_type(ty["inner"]["trait"]) + + +work_list = set([crate["root"]]) +visited = work_list.copy() + +while work_list: + current = work_list.pop() + visited.add(current) + item = get_local_item(current) + # check intradoc links + for (_name, link) in item["links"].items(): + if not valid_id(link): + print("Intra-doc link contains invalid ID:", link) + + # check all fields that reference types such as generics as well as nested items + # (modules, structs, traits, and enums) + if item["kind"] == "module": + work_list |= set(item["inner"]["items"]) - visited + elif item["kind"] == "struct": + check_generics(item["inner"]["generics"]) + work_list |= ( + set(item["inner"]["fields"]) | set(item["inner"]["impls"]) + ) - visited + elif item["kind"] == "struct_field": + check_type(item["inner"]) + elif item["kind"] == "enum": + check_generics(item["inner"]["generics"]) + work_list |= ( + set(item["inner"]["variants"]) | set(item["inner"]["impls"]) + ) - visited + elif item["kind"] == "variant": + if item["inner"]["variant_kind"] == "tuple": + for ty in item["inner"]["variant_inner"]: + check_type(ty) + elif item["inner"]["variant_kind"] == "struct": + work_list |= set(item["inner"]["variant_inner"]) - visited + elif item["kind"] in ("function", "method"): + check_generics(item["inner"]["generics"]) + check_decl(item["inner"]["decl"]) + elif item["kind"] in ("static", "constant", "assoc_const"): + check_type(item["inner"]["type"]) + elif item["kind"] == "typedef": + check_type(item["inner"]["type"]) + check_generics(item["inner"]["generics"]) + elif item["kind"] == "opaque_ty": + check_generics(item["inner"]["generics"]) + for bound in item["inner"]["bounds"]: + check_generic_bound(bound) + elif item["kind"] == "trait_alias": + check_generics(item["inner"]["params"]) + for bound in item["inner"]["bounds"]: + check_generic_bound(bound) + elif item["kind"] == "trait": + check_generics(item["inner"]["generics"]) + for bound in item["inner"]["bounds"]: + check_generic_bound(bound) + work_list |= ( + set(item["inner"]["items"]) | set(item["inner"]["implementors"]) + ) - visited + elif item["kind"] == "impl": + check_generics(item["inner"]["generics"]) + if item["inner"]["trait"]: + check_type(item["inner"]["trait"]) + if item["inner"]["blanket_impl"]: + check_type(item["inner"]["blanket_impl"]) + check_type(item["inner"]["for"]) + for assoc_item in item["inner"]["items"]: + if not valid_id(assoc_item): + print("Impl block referenced a missing ID:", assoc_item) + sys.exit(1) + elif item["kind"] == "assoc_type": + for bound in item["inner"]["bounds"]: + check_generic_bound(bound) + if item["inner"]["default"]: + check_type(item["inner"]["default"]) diff --git a/src/test/rustdoc-json/compare.py b/src/test/rustdoc-json/compare.py new file mode 100644 index 0000000000000..b0c5b16a19700 --- /dev/null +++ b/src/test/rustdoc-json/compare.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python + +# This script can check that an expected json blob is a subset of what actually gets produced. +# The comparison is independent of the value of IDs (which are unstable) and instead uses their +# relative ordering to check them against eachother by looking them up in their respective blob's +# `index` or `paths` mappings. To add a new test run `rustdoc --output-format json -o . yourtest.rs` +# and then create `yourtest.expected` by stripping unnecessary details from `yourtest.json`. If +# you're on windows, replace `\` with `/`. + +import copy +import sys +import json +import types + +# Used instead of the string ids when used as references. +# Not used as keys in `index` or `paths` +class ID(str): + pass + + +class SubsetException(Exception): + def __init__(self, msg, trace): + self.msg = msg + self.trace = msg + super().__init__("{}: {}".format(trace, msg)) + + +def check_subset(expected_main, actual_main, base_dir): + expected_index = expected_main["index"] + expected_paths = expected_main["paths"] + actual_index = actual_main["index"] + actual_paths = actual_main["paths"] + already_checked = set() + + def _check_subset(expected, actual, trace): + expected_type = type(expected) + actual_type = type(actual) + + if actual_type is str: + actual = normalize(actual).replace(base_dir, "$TEST_BASE_DIR") + + if expected_type is not actual_type: + raise SubsetException( + "expected type `{}`, got `{}`".format(expected_type, actual_type), trace + ) + + + if expected_type in (int, bool, str) and expected != actual: + raise SubsetException("expected `{}`, got: `{}`".format(expected, actual), trace) + if expected_type is dict: + for key in expected: + if key not in actual: + raise SubsetException( + "Key `{}` not found in output".format(key), trace + ) + new_trace = copy.deepcopy(trace) + new_trace.append(key) + _check_subset(expected[key], actual[key], new_trace) + elif expected_type is list: + expected_elements = len(expected) + actual_elements = len(actual) + if expected_elements != actual_elements: + raise SubsetException( + "Found {} items, expected {}".format( + expected_elements, actual_elements + ), + trace, + ) + for expected, actual in zip(expected, actual): + new_trace = copy.deepcopy(trace) + new_trace.append(expected) + _check_subset(expected, actual, new_trace) + elif expected_type is ID and expected not in already_checked: + already_checked.add(expected) + _check_subset( + expected_index.get(expected, {}), actual_index.get(actual, {}), trace + ) + _check_subset( + expected_paths.get(expected, {}), actual_paths.get(actual, {}), trace + ) + + _check_subset(expected_main["root"], actual_main["root"], []) + + +def rustdoc_object_hook(obj): + # No need to convert paths, index and external_crates keys to ids, since + # they are the target of resolution, and never a source itself. + if "id" in obj and obj["id"]: + obj["id"] = ID(obj["id"]) + if "root" in obj: + obj["root"] = ID(obj["root"]) + if "items" in obj: + obj["items"] = [ID(id) for id in obj["items"]] + if "variants" in obj: + obj["variants"] = [ID(id) for id in obj["variants"]] + if "fields" in obj: + obj["fields"] = [ID(id) for id in obj["fields"]] + if "impls" in obj: + obj["impls"] = [ID(id) for id in obj["impls"]] + if "implementors" in obj: + obj["implementors"] = [ID(id) for id in obj["implementors"]] + if "links" in obj: + obj["links"] = {s: ID(id) for s, id in obj["links"]} + if "variant_kind" in obj and obj["variant_kind"] == "struct": + obj["variant_inner"] = [ID(id) for id in obj["variant_inner"]] + return obj + + +def main(expected_fpath, actual_fpath, base_dir): + print( + "checking that {} is a logical subset of {}".format( + expected_fpath, actual_fpath + ) + ) + with open(expected_fpath) as expected_file: + expected_main = json.load(expected_file, object_hook=rustdoc_object_hook) + with open(actual_fpath) as actual_file: + actual_main = json.load(actual_file, object_hook=rustdoc_object_hook) + check_subset(expected_main, actual_main, base_dir) + print("all checks passed") + +def normalize(s): + return s.replace('\\', '/') + +if __name__ == "__main__": + if len(sys.argv) < 4: + print("Usage: `compare.py expected.json actual.json test-dir`") + else: + main(sys.argv[1], sys.argv[2], normalize(sys.argv[3])) diff --git a/src/test/rustdoc-json/structs.expected b/src/test/rustdoc-json/structs.expected new file mode 100644 index 0000000000000..799829de3fd6c --- /dev/null +++ b/src/test/rustdoc-json/structs.expected @@ -0,0 +1,456 @@ +{ + "root": "0:0", + "version": null, + "includes_private": false, + "index": { + "0:9": { + "crate_id": 0, + "name": "Unit", + "source": { + "filename": "$TEST_BASE_DIR/structs.rs", + "begin": [ + 7, + 0 + ], + "end": [ + 7, + 16 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "unit", + "generics": { + "params": [], + "where_predicates": [] + }, + "fields_stripped": false, + "fields": [] + } + }, + "0:8": { + "crate_id": 0, + "name": "1", + "source": { + "filename": "$TEST_BASE_DIR/structs.rs", + "begin": [ + 5, + 22 + ], + "end": [ + 5, + 28 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "resolved_path", + "inner": { + "name": "String", + "id": "5:5035", + "args": { + "angle_bracketed": { + "args": [], + "bindings": [] + } + }, + "param_names": [] + } + } + }, + "0:18": { + "crate_id": 0, + "name": "stuff", + "source": { + "filename": "$TEST_BASE_DIR/structs.rs", + "begin": [ + 15, + 4 + ], + "end": [ + 15, + 17 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "resolved_path", + "inner": { + "name": "Vec", + "id": "5:4322", + "args": { + "angle_bracketed": { + "args": [ + { + "type": { + "kind": "generic", + "inner": "T" + } + } + ], + "bindings": [] + } + }, + "param_names": [] + } + } + }, + "0:11": { + "crate_id": 0, + "name": "WithPrimitives", + "source": { + "filename": "$TEST_BASE_DIR/structs.rs", + "begin": [ + 9, + 0 + ], + "end": [ + 12, + 1 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "plain", + "generics": { + "params": [ + { + "name": "'a", + "kind": "lifetime" + } + ], + "where_predicates": [] + }, + "fields_stripped": true + } + }, + "0:14": { + "crate_id": 0, + "name": "s", + "source": { + "filename": "$TEST_BASE_DIR/structs.rs", + "begin": [ + 11, + 4 + ], + "end": [ + 11, + 14 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "borrowed_ref", + "inner": { + "lifetime": "'a", + "mutable": false, + "type": { + "kind": "primitive", + "inner": "str" + } + } + } + }, + "0:19": { + "crate_id": 0, + "name": "things", + "source": { + "filename": "$TEST_BASE_DIR/structs.rs", + "begin": [ + 16, + 4 + ], + "end": [ + 16, + 25 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "resolved_path", + "inner": { + "name": "HashMap", + "id": "1:6600", + "args": { + "angle_bracketed": { + "args": [ + { + "type": { + "kind": "generic", + "inner": "U" + } + }, + { + "type": { + "kind": "generic", + "inner": "U" + } + } + ], + "bindings": [] + } + }, + "param_names": [] + } + } + }, + "0:15": { + "crate_id": 0, + "name": "WithGenerics", + "source": { + "filename": "$TEST_BASE_DIR/structs.rs", + "begin": [ + 14, + 0 + ], + "end": [ + 17, + 1 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "plain", + "generics": { + "params": [ + { + "name": "T", + "kind": { + "type": { + "bounds": [], + "default": null + } + } + }, + { + "name": "U", + "kind": { + "type": { + "bounds": [], + "default": null + } + } + } + ], + "where_predicates": [] + }, + "fields_stripped": true + } + }, + "0:0": { + "crate_id": 0, + "name": "structs", + "source": { + "filename": "$TEST_BASE_DIR/structs.rs", + "begin": [ + 1, + 0 + ], + "end": [ + 17, + 1 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "module", + "inner": { + "is_crate": true, + "items": [ + "0:4", + "0:5", + "0:9", + "0:11", + "0:15" + ] + } + }, + "0:13": { + "crate_id": 0, + "name": "num", + "source": { + "filename": "$TEST_BASE_DIR/structs.rs", + "begin": [ + 10, + 4 + ], + "end": [ + 10, + 12 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "primitive", + "inner": "u32" + } + }, + "0:5": { + "crate_id": 0, + "name": "Tuple", + "source": { + "filename": "$TEST_BASE_DIR/structs.rs", + "begin": [ + 5, + 0 + ], + "end": [ + 5, + 30 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "tuple", + "generics": { + "params": [], + "where_predicates": [] + }, + "fields_stripped": true + } + }, + "0:4": { + "crate_id": 0, + "name": "PlainEmpty", + "source": { + "filename": "$TEST_BASE_DIR/structs.rs", + "begin": [ + 3, + 0 + ], + "end": [ + 3, + 24 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "plain", + "generics": { + "params": [], + "where_predicates": [] + }, + "fields_stripped": false, + "fields": [] + } + }, + "0:7": { + "crate_id": 0, + "name": "0", + "source": { + "filename": "$TEST_BASE_DIR/structs.rs", + "begin": [ + 5, + 17 + ], + "end": [ + 5, + 20 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "primitive", + "inner": "u32" + } + } + }, + "paths": { + "5:4322": { + "crate_id": 5, + "path": [ + "alloc", + "vec", + "Vec" + ], + "kind": "struct" + }, + "5:5035": { + "crate_id": 5, + "path": [ + "alloc", + "string", + "String" + ], + "kind": "struct" + }, + "1:6600": { + "crate_id": 1, + "path": [ + "std", + "collections", + "hash", + "map", + "HashMap" + ], + "kind": "struct" + } + }, + "external_crates": { + "1": { + "name": "std" + }, + "5": { + "name": "alloc" + } + }, + "format_version": 1 +} diff --git a/src/test/rustdoc-json/structs.rs b/src/test/rustdoc-json/structs.rs new file mode 100644 index 0000000000000..43fc4743503aa --- /dev/null +++ b/src/test/rustdoc-json/structs.rs @@ -0,0 +1,17 @@ +use std::collections::HashMap; + +pub struct PlainEmpty {} + +pub struct Tuple(u32, String); + +pub struct Unit; + +pub struct WithPrimitives<'a> { + num: u32, + s: &'a str, +} + +pub struct WithGenerics { + stuff: Vec, + things: HashMap, +} diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr index 3ba0ba6107531..1c7fc83bb8dea 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr +++ b/src/test/rustdoc-ui/check-doc-alias-attr.stderr @@ -1,16 +1,16 @@ -error: doc alias attribute expects a string: #[doc(alias = "0")] +error: doc alias attribute expects a string: #[doc(alias = "a")] --> $DIR/check-doc-alias-attr.rs:6:7 | LL | #[doc(alias)] | ^^^^^ -error: doc alias attribute expects a string: #[doc(alias = "0")] +error: doc alias attribute expects a string: #[doc(alias = "a")] --> $DIR/check-doc-alias-attr.rs:7:7 | LL | #[doc(alias = 0)] | ^^^^^^^^^ -error: doc alias attribute expects a string: #[doc(alias = "0")] +error: doc alias attribute expects a string: #[doc(alias = "a")] --> $DIR/check-doc-alias-attr.rs:8:7 | LL | #[doc(alias("bar"))] diff --git a/src/test/rustdoc/intra-doc/raw-ident-self.rs b/src/test/rustdoc/intra-doc/raw-ident-self.rs new file mode 100644 index 0000000000000..d289797f14652 --- /dev/null +++ b/src/test/rustdoc/intra-doc/raw-ident-self.rs @@ -0,0 +1,13 @@ +#![deny(broken_intra_doc_links)] +pub mod r#impl { + pub struct S; + + impl S { + /// See [Self::b]. + // @has raw_ident_self/impl/struct.S.html + // @has - '//a[@href="../../raw_ident_self/impl/struct.S.html#method.b"]' 'Self::b' + pub fn a() {} + + pub fn b() {} + } +} diff --git a/src/test/rustdoc/plain-text-summaries.rs b/src/test/rustdoc/markdown-summaries.rs similarity index 55% rename from src/test/rustdoc/plain-text-summaries.rs rename to src/test/rustdoc/markdown-summaries.rs index c995ccbf0af67..b843e28e7b0d3 100644 --- a/src/test/rustdoc/plain-text-summaries.rs +++ b/src/test/rustdoc/markdown-summaries.rs @@ -1,21 +1,22 @@ #![crate_type = "lib"] #![crate_name = "summaries"] -//! This summary has a [link] and `code`. +//! This *summary* has a [link] and `code`. //! //! This is the second paragraph. //! //! [link]: https://example.com -// @has search-index.js 'This summary has a link and `code`.' +// @has search-index.js 'This summary has a link and code.' // @!has - 'second paragraph' -/// This `code` should be in backticks. +/// This `code` will be rendered in a code tag. /// /// This text should not be rendered. pub struct Sidebar; -// @has summaries/sidebar-items.js 'This `code` should be in backticks.' +// @has search-index.js 'This code will be rendered in a code tag.' +// @has summaries/sidebar-items.js 'This `code` will be rendered in a code tag.' // @!has - 'text should not be rendered' /// ```text diff --git a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs new file mode 100644 index 0000000000000..053712a4b4ee6 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs @@ -0,0 +1,11 @@ +// compile-flags: -Z unstable-options + +#![feature(rustc_private)] +#![feature(doc_keyword)] + +#![crate_type = "lib"] + +#![deny(rustc::existing_doc_keyword)] + +#[doc(keyword = "tadam")] //~ ERROR +mod tadam {} diff --git a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr new file mode 100644 index 0000000000000..bac44f338b74c --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr @@ -0,0 +1,15 @@ +error: Found non-existing keyword `tadam` used in `#[doc(keyword = "...")]` + --> $DIR/existing_doc_keyword.rs:10:1 + | +LL | #[doc(keyword = "tadam")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/existing_doc_keyword.rs:8:9 + | +LL | #![deny(rustc::existing_doc_keyword)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: only existing keywords are allowed in core/std + +error: aborting due to previous error + diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs index 35ddab95831db..4833f6971c171 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs +++ b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs @@ -6,12 +6,12 @@ //~^ WARN use of deprecated attribute `plugin` #![forbid(test_lint)] -fn lintme() { } //~ ERROR item is named 'lintme' +fn lintme() {} //~ ERROR item is named 'lintme' #[allow(test_lint)] -//~^ ERROR allow(test_lint) overruled by outer forbid(test_lint) -//~| ERROR allow(test_lint) overruled by outer forbid(test_lint) -//~| ERROR allow(test_lint) overruled by outer forbid(test_lint) +//~^ ERROR allow(test_lint) incompatible +//~| ERROR allow(test_lint) incompatible +//~| ERROR allow(test_lint) incompatible pub fn main() { lintme(); } diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr index 7b868c3393f50..e11a4f8449352 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr +++ b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr @@ -1,4 +1,4 @@ -error[E0453]: allow(test_lint) overruled by outer forbid(test_lint) +error[E0453]: allow(test_lint) incompatible with previous forbid --> $DIR/lint-plugin-forbid-attrs.rs:11:9 | LL | #![forbid(test_lint)] @@ -7,7 +7,7 @@ LL | #![forbid(test_lint)] LL | #[allow(test_lint)] | ^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(test_lint) overruled by outer forbid(test_lint) +error[E0453]: allow(test_lint) incompatible with previous forbid --> $DIR/lint-plugin-forbid-attrs.rs:11:9 | LL | #![forbid(test_lint)] @@ -27,8 +27,8 @@ LL | #![plugin(lint_plugin_test)] error: item is named 'lintme' --> $DIR/lint-plugin-forbid-attrs.rs:9:1 | -LL | fn lintme() { } - | ^^^^^^^^^^^^^^^ +LL | fn lintme() {} + | ^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/lint-plugin-forbid-attrs.rs:7:11 @@ -36,7 +36,7 @@ note: the lint level is defined here LL | #![forbid(test_lint)] | ^^^^^^^^^ -error[E0453]: allow(test_lint) overruled by outer forbid(test_lint) +error[E0453]: allow(test_lint) incompatible with previous forbid --> $DIR/lint-plugin-forbid-attrs.rs:11:9 | LL | #![forbid(test_lint)] diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs index 695d3aef16905..ce034ee38d70c 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs +++ b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs @@ -7,9 +7,9 @@ //~^ WARN use of deprecated attribute `plugin` fn lintme() { } //~ ERROR item is named 'lintme' -#[allow(test_lint)] //~ ERROR allow(test_lint) overruled by outer forbid(test_lint) - //~| ERROR allow(test_lint) overruled by outer forbid(test_lint) - //~| ERROR allow(test_lint) overruled by outer forbid(test_lint) +#[allow(test_lint)] //~ ERROR allow(test_lint) incompatible + //~| ERROR allow(test_lint) incompatible + //~| ERROR allow(test_lint) pub fn main() { lintme(); } diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr index e9ec63ef9831a..09c19af617a29 100644 --- a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr +++ b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr @@ -1,4 +1,4 @@ -error[E0453]: allow(test_lint) overruled by outer forbid(test_lint) +error[E0453]: allow(test_lint) incompatible with previous forbid --> $DIR/lint-plugin-forbid-cmdline.rs:10:9 | LL | #[allow(test_lint)] @@ -6,7 +6,7 @@ LL | #[allow(test_lint)] | = note: `forbid` lint level was set on command line -error[E0453]: allow(test_lint) overruled by outer forbid(test_lint) +error[E0453]: allow(test_lint) incompatible with previous forbid --> $DIR/lint-plugin-forbid-cmdline.rs:10:9 | LL | #[allow(test_lint)] @@ -30,7 +30,7 @@ LL | fn lintme() { } | = note: requested on the command line with `-F test-lint` -error[E0453]: allow(test_lint) overruled by outer forbid(test_lint) +error[E0453]: allow(test_lint) incompatible with previous forbid --> $DIR/lint-plugin-forbid-cmdline.rs:10:9 | LL | #[allow(test_lint)] diff --git a/src/test/ui/allocator/custom.rs b/src/test/ui/allocator/custom.rs index dfb5d3e9e38d0..10cbc23c427f0 100644 --- a/src/test/ui/allocator/custom.rs +++ b/src/test/ui/allocator/custom.rs @@ -8,9 +8,8 @@ extern crate helper; -use std::alloc::{self, AllocRef, Global, Layout, System}; +use std::alloc::{self, Allocator, Global, Layout, System}; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::ptr::NonNull; static HITS: AtomicUsize = AtomicUsize::new(0); @@ -24,7 +23,7 @@ unsafe impl alloc::GlobalAlloc for A { unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { HITS.fetch_add(1, Ordering::SeqCst); - AllocRef::dealloc(&System, NonNull::new(ptr).unwrap(), layout) + alloc::GlobalAlloc::dealloc(&System, ptr, layout) } } @@ -39,10 +38,10 @@ fn main() { unsafe { let layout = Layout::from_size_align(4, 2).unwrap(); - let memory = Global.alloc(layout.clone()).unwrap(); + let memory = Global.allocate(layout.clone()).unwrap(); helper::work_with(&memory); assert_eq!(HITS.load(Ordering::SeqCst), n + 1); - Global.dealloc(memory.as_non_null_ptr(), layout); + Global.deallocate(memory.as_non_null_ptr(), layout); assert_eq!(HITS.load(Ordering::SeqCst), n + 2); let s = String::with_capacity(10); @@ -51,10 +50,10 @@ fn main() { drop(s); assert_eq!(HITS.load(Ordering::SeqCst), n + 4); - let memory = System.alloc(layout.clone()).unwrap(); - assert_eq!(HITS.load(Ordering::SeqCst), n + 4); + let memory = System.allocate(layout.clone()).unwrap(); helper::work_with(&memory); - System.dealloc(memory.as_non_null_ptr(), layout); + assert_eq!(HITS.load(Ordering::SeqCst), n + 4); + System.deallocate(memory.as_non_null_ptr(), layout); assert_eq!(HITS.load(Ordering::SeqCst), n + 4); } } diff --git a/src/test/ui/allocator/xcrate-use.rs b/src/test/ui/allocator/xcrate-use.rs index a1446b3664d4b..edd4df75e8b83 100644 --- a/src/test/ui/allocator/xcrate-use.rs +++ b/src/test/ui/allocator/xcrate-use.rs @@ -10,7 +10,7 @@ extern crate custom; extern crate helper; -use std::alloc::{AllocRef, Global, Layout, System}; +use std::alloc::{Allocator, Global, Layout, System}; use std::sync::atomic::{AtomicUsize, Ordering}; #[global_allocator] @@ -21,16 +21,16 @@ fn main() { let n = GLOBAL.0.load(Ordering::SeqCst); let layout = Layout::from_size_align(4, 2).unwrap(); - let memory = Global.alloc(layout.clone()).unwrap(); + let memory = Global.allocate(layout.clone()).unwrap(); helper::work_with(&memory); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1); - Global.dealloc(memory.as_non_null_ptr(), layout); + Global.deallocate(memory.as_non_null_ptr(), layout); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); - let memory = System.alloc(layout.clone()).unwrap(); + let memory = System.allocate(layout.clone()).unwrap(); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); helper::work_with(&memory); - System.dealloc(memory.as_non_null_ptr(), layout); + System.deallocate(memory.as_non_null_ptr(), layout); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); } } diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs deleted file mode 100644 index 1b6d6d0ff599f..0000000000000 --- a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs +++ /dev/null @@ -1,12 +0,0 @@ -// ignore-tidy-linelength - -trait Foo { - type Item; -} -trait Bar { - type Item; -} -trait Baz: Foo + Bar {} -//~^ ERROR cycle detected when computing the super traits of `Baz` with associated type name `Item` [E0391] - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr deleted file mode 100644 index bda1debeac0d6..0000000000000 --- a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0391]: cycle detected when computing the super traits of `Baz` with associated type name `Item` - --> $DIR/ambiguous-associated-type2.rs:9:1 - | -LL | trait Baz: Foo + Bar {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: ...which again requires computing the super traits of `Baz` with associated type name `Item`, completing the cycle -note: cycle used when computing the super traits of `Baz` - --> $DIR/ambiguous-associated-type2.rs:9:1 - | -LL | trait Baz: Foo + Bar {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs b/src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs deleted file mode 100644 index 3eb50ab554735..0000000000000 --- a/src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs +++ /dev/null @@ -1,21 +0,0 @@ -// check-pass - -trait Foo { - type Item; -} - -trait Bar -where - Self: Foo, -{ -} - -#[allow(dead_code)] -fn foo(_m: M) -where - M: Bar, - M::Item: Send, -{ -} - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs b/src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs deleted file mode 100644 index b1e54ec04493b..0000000000000 --- a/src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs +++ /dev/null @@ -1,10 +0,0 @@ -// check-pass - -trait Foo {} -trait Bar { - type A; - type B; -} -trait Baz: Bar + Foo {} - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs b/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs deleted file mode 100644 index 07d0f8f8769e5..0000000000000 --- a/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[allow(dead_code)] -fn foo(_m: M) -where - M::Item: Temp, - //~^ ERROR cannot find trait `Temp` in this scope [E0405] - //~| ERROR associated type `Item` not found for `M` [E0220] -{ -} - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr b/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr deleted file mode 100644 index bc2807b03961c..0000000000000 --- a/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0405]: cannot find trait `Temp` in this scope - --> $DIR/missing-trait-bound-for-assoc-fails.rs:4:14 - | -LL | M::Item: Temp, - | ^^^^ not found in this scope - -error[E0220]: associated type `Item` not found for `M` - --> $DIR/missing-trait-bound-for-assoc-fails.rs:4:8 - | -LL | M::Item: Temp, - | ^^^^ associated type `Item` not found - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0220, E0405. -For more information about an error, try `rustc --explain E0220`. diff --git a/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs b/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs deleted file mode 100644 index c82ec01f4d61d..0000000000000 --- a/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs +++ /dev/null @@ -1,12 +0,0 @@ -// check-pass -trait Foo { - type Bar; -} -trait Qux: Foo + AsRef {} -trait Foo2 {} - -trait Qux2: Foo2 + AsRef { - type Bar; -} - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/super-trait-referencing.rs b/src/test/ui/associated-type-bounds/super-trait-referencing.rs deleted file mode 100644 index 2e97535157fd2..0000000000000 --- a/src/test/ui/associated-type-bounds/super-trait-referencing.rs +++ /dev/null @@ -1,19 +0,0 @@ -// check-pass - -// The goal of this test is to ensure that T: Bar -// in the where clause does not cycle - -trait Foo { - type Item; -} - -trait Bar {} - -fn baz() -where - T: Foo, - T: Bar, -{ -} - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs b/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs deleted file mode 100644 index 72a6be9ffc388..0000000000000 --- a/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs +++ /dev/null @@ -1,27 +0,0 @@ -// check-pass - -// Test that we do not get a cycle due to -// resolving `Self::Bar` in the where clauses -// on a trait definition (in particular, in -// a where clause that is defining a superpredicate). - -trait Foo { - type Bar; -} -trait Qux -where - Self: Foo, - Self: AsRef, -{ -} -trait Foo2 {} - -trait Qux2 -where - Self: Foo2, - Self: AsRef, -{ - type Bar; -} - -fn main() {} diff --git a/src/test/ui/associated-types/defaults-wf.stderr b/src/test/ui/associated-types/defaults-wf.stderr index 26c852601941a..4c43e6a182dc9 100644 --- a/src/test/ui/associated-types/defaults-wf.stderr +++ b/src/test/ui/associated-types/defaults-wf.stderr @@ -6,7 +6,7 @@ LL | type Ty = Vec<[u8]>; | ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | -LL | pub struct Vec { +LL | pub struct Vec { | - required by this bound in `Vec` | = help: the trait `Sized` is not implemented for `[u8]` diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr index c9255c91d2d02..042223f3e9587 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr @@ -12,7 +12,6 @@ LL | type U = str; | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr index 225b18a3b0454..848924bf58eff 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr @@ -12,7 +12,6 @@ LL | fn f<'a, T: X<'a> + ?Sized>(x: &>::U) { | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr index 7af261e4b3d4f..d35c127926431 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr @@ -12,7 +12,6 @@ LL | type V = str; | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr index b48ff97f1211b..0afa340f7a148 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr @@ -12,7 +12,6 @@ LL | for<'b> >::W: Clone, | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error[E0277]: the trait bound `for<'b> >::W: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-2.rs:16:14 @@ -28,7 +27,6 @@ LL | type W = str; | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error[E0277]: the trait bound `for<'b> >::W: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-2.rs:4:8 @@ -44,7 +42,6 @@ LL | for<'b> >::W: Clone, | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error: aborting due to 3 previous errors diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr index 48c4d77dcc7d4..79e1e00e98d77 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr @@ -12,7 +12,6 @@ LL | type U = str; | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr index 111ca8566b195..e23ac5f56503b 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr @@ -12,7 +12,6 @@ LL | type U = str; | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr index df25f7ac953e7..38909be59f237 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr @@ -12,7 +12,6 @@ LL | type U = str; | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error[E0277]: the trait bound `for<'b> as X<'b, Vec>>::U: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-5.rs:27:14 @@ -28,7 +27,6 @@ LL | type U = str; | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error[E0277]: the trait bound `for<'b> as X<'b, Vec>>::U: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-5.rs:33:14 @@ -44,7 +42,6 @@ LL | type U = str; | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error[E0277]: the trait bound `for<'b> as X<'b, Box>>::U: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-5.rs:33:14 @@ -60,7 +57,6 @@ LL | type U = str; | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error: aborting due to 4 previous errors diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr index 2efdb2445af21..6e02b42e514c5 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr @@ -12,7 +12,6 @@ LL | type U = str; | = help: the following implementations were found: <&T as Clone> - <&mut T as Clone> error[E0277]: the trait bound `for<'b> T: X<'b, T>` is not satisfied --> $DIR/hr-associated-type-bound-param-6.rs:12:12 diff --git a/src/test/ui/async-await/issue-64130-3-other.stderr b/src/test/ui/async-await/issue-64130-3-other.stderr index 4bf43f14cc195..9ffdd0524c663 100644 --- a/src/test/ui/async-await/issue-64130-3-other.stderr +++ b/src/test/ui/async-await/issue-64130-3-other.stderr @@ -10,8 +10,6 @@ LL | async fn bar() { LL | is_qux(bar()); | ^^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo` | - = help: the following implementations were found: - note: future does not implement `Qux` as this value is used across an await --> $DIR/issue-64130-3-other.rs:18:5 | diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr index 53ba9b8a3f6b4..c2eab1a33b91a 100644 --- a/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr @@ -7,8 +7,6 @@ LL | fn is_mytrait() {} LL | is_mytrait::<(MyS2, MyS)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2` | - = help: the following implementations were found: - = note: required because it appears within the type `(MyS2, MyS)` error: aborting due to previous error diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr index bc50000498463..efb6bde17990f 100644 --- a/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr @@ -6,9 +6,6 @@ LL | fn is_mytrait() {} ... LL | is_mytrait::(); | ^^^^ the trait `MyTrait` is not implemented for `MyS2` - | - = help: the following implementations were found: - error: aborting due to previous error diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-negation.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-negation.stderr index 76a6994cb009a..dae87bc221a6f 100644 --- a/src/test/ui/auto-traits/typeck-default-trait-impl-negation.stderr +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-negation.stderr @@ -6,9 +6,6 @@ LL | fn is_my_trait() {} ... LL | is_my_trait::(); | ^^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `ThisImplsUnsafeTrait` - | - = help: the following implementations were found: - error[E0277]: the trait bound `ThisImplsTrait: MyUnsafeTrait` is not satisfied --> $DIR/typeck-default-trait-impl-negation.rs:25:26 @@ -18,9 +15,6 @@ LL | fn is_my_unsafe_trait() {} ... LL | is_my_unsafe_trait::(); | ^^^^^^^^^^^^^^ the trait `MyUnsafeTrait` is not implemented for `ThisImplsTrait` - | - = help: the following implementations were found: - error: aborting due to 2 previous errors diff --git a/src/test/ui/bad/bad-sized.stderr b/src/test/ui/bad/bad-sized.stderr index 10d12a09b2579..60a5bb9f78666 100644 --- a/src/test/ui/bad/bad-sized.stderr +++ b/src/test/ui/bad/bad-sized.stderr @@ -17,7 +17,7 @@ LL | let x: Vec = Vec::new(); | ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | -LL | pub struct Vec { +LL | pub struct Vec { | - required by this bound in `Vec` | = help: the trait `Sized` is not implemented for `dyn Trait` diff --git a/src/test/ui/box/leak-alloc.rs b/src/test/ui/box/leak-alloc.rs index 2e73d6f143213..3f0f39f448b91 100644 --- a/src/test/ui/box/leak-alloc.rs +++ b/src/test/ui/box/leak-alloc.rs @@ -1,26 +1,26 @@ #![feature(allocator_api)] -use std::alloc::{AllocError, AllocRef, Layout, System}; +use std::alloc::{AllocError, Allocator, Layout, System}; use std::ptr::NonNull; use std::boxed::Box; -struct Allocator {} +struct Alloc {} -unsafe impl AllocRef for Allocator { - fn alloc(&self, layout: Layout) -> Result, AllocError> { - System.alloc(layout) +unsafe impl Allocator for Alloc { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + System.allocate(layout) } - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { - System.dealloc(ptr, layout) + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + System.deallocate(ptr, layout) } } fn use_value(_: u32) {} fn main() { - let alloc = Allocator {}; + let alloc = Alloc {}; let boxed = Box::new_in(10, alloc.by_ref()); let theref = Box::leak(boxed); drop(alloc); diff --git a/src/test/ui/check-doc-alias-attr.stderr b/src/test/ui/check-doc-alias-attr.stderr index a92298d163380..dce325f9d3898 100644 --- a/src/test/ui/check-doc-alias-attr.stderr +++ b/src/test/ui/check-doc-alias-attr.stderr @@ -1,16 +1,16 @@ -error: doc alias attribute expects a string: #[doc(alias = "0")] +error: doc alias attribute expects a string: #[doc(alias = "a")] --> $DIR/check-doc-alias-attr.rs:7:7 | LL | #[doc(alias)] | ^^^^^ -error: doc alias attribute expects a string: #[doc(alias = "0")] +error: doc alias attribute expects a string: #[doc(alias = "a")] --> $DIR/check-doc-alias-attr.rs:8:7 | LL | #[doc(alias = 0)] | ^^^^^^^^^ -error: doc alias attribute expects a string: #[doc(alias = "0")] +error: doc alias attribute expects a string: #[doc(alias = "a")] --> $DIR/check-doc-alias-attr.rs:9:7 | LL | #[doc(alias("bar"))] diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs new file mode 100644 index 0000000000000..0b94317fd7136 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs @@ -0,0 +1,86 @@ +// Test that arrays are completely captured by closures by relying on the borrow check diagnostics + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +fn arrays_1() { + let mut arr = [1, 2, 3, 4, 5]; + + let mut c = || { + arr[0] += 10; + }; + + // c will capture `arr` completely, therefore another index into the + // array can't be modified here + arr[1] += 10; + //~^ ERROR: cannot use `arr` because it was mutably borrowed + //~| ERROR: cannot use `arr[_]` because it was mutably borrowed + c(); +} + +fn arrays_2() { + let mut arr = [1, 2, 3, 4, 5]; + + let c = || { + println!("{:#?}", &arr[3..4]); + }; + + // c will capture `arr` completely, therefore another index into the + // array can't be modified here + arr[1] += 10; + //~^ ERROR: cannot assign to `arr[_]` because it is borrowed + c(); +} + +fn arrays_3() { + let mut arr = [1, 2, 3, 4, 5]; + + let c = || { + println!("{}", arr[3]); + }; + + // c will capture `arr` completely, therefore another index into the + // array can't be modified here + arr[1] += 10; + //~^ ERROR: cannot assign to `arr[_]` because it is borrowed + c(); +} + +fn arrays_4() { + let mut arr = [1, 2, 3, 4, 5]; + + let mut c = || { + arr[1] += 10; + }; + + // c will capture `arr` completely, therefore we cannot borrow another index + // into the array. + println!("{}", arr[3]); + //~^ ERROR: cannot use `arr` because it was mutably borrowed + //~| ERROR: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable + + c(); +} + +fn arrays_5() { + let mut arr = [1, 2, 3, 4, 5]; + + let mut c = || { + arr[1] += 10; + }; + + // c will capture `arr` completely, therefore we cannot borrow other indecies + // into the array. + println!("{:#?}", &arr[3..2]); + //~^ ERROR: cannot borrow `arr` as immutable because it is also borrowed as mutable + + c(); +} + +fn main() { + arrays_1(); + arrays_2(); + arrays_3(); + arrays_4(); + arrays_5(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr new file mode 100644 index 0000000000000..77e3e71bc6120 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr @@ -0,0 +1,111 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/arrays.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0503]: cannot use `arr` because it was mutably borrowed + --> $DIR/arrays.rs:15:5 + | +LL | let mut c = || { + | -- borrow of `arr` occurs here +LL | arr[0] += 10; + | --- borrow occurs due to use of `arr` in closure +... +LL | arr[1] += 10; + | ^^^^^^ use of borrowed `arr` +... +LL | c(); + | - borrow later used here + +error[E0503]: cannot use `arr[_]` because it was mutably borrowed + --> $DIR/arrays.rs:15:5 + | +LL | let mut c = || { + | -- borrow of `arr` occurs here +LL | arr[0] += 10; + | --- borrow occurs due to use of `arr` in closure +... +LL | arr[1] += 10; + | ^^^^^^^^^^^^ use of borrowed `arr` +... +LL | c(); + | - borrow later used here + +error[E0506]: cannot assign to `arr[_]` because it is borrowed + --> $DIR/arrays.rs:30:5 + | +LL | let c = || { + | -- borrow of `arr[_]` occurs here +LL | println!("{:#?}", &arr[3..4]); + | --- borrow occurs due to use in closure +... +LL | arr[1] += 10; + | ^^^^^^^^^^^^ assignment to borrowed `arr[_]` occurs here +LL | +LL | c(); + | - borrow later used here + +error[E0506]: cannot assign to `arr[_]` because it is borrowed + --> $DIR/arrays.rs:44:5 + | +LL | let c = || { + | -- borrow of `arr[_]` occurs here +LL | println!("{}", arr[3]); + | --- borrow occurs due to use in closure +... +LL | arr[1] += 10; + | ^^^^^^^^^^^^ assignment to borrowed `arr[_]` occurs here +LL | +LL | c(); + | - borrow later used here + +error[E0503]: cannot use `arr` because it was mutably borrowed + --> $DIR/arrays.rs:58:20 + | +LL | let mut c = || { + | -- borrow of `arr` occurs here +LL | arr[1] += 10; + | --- borrow occurs due to use of `arr` in closure +... +LL | println!("{}", arr[3]); + | ^^^^^^ use of borrowed `arr` +... +LL | c(); + | - borrow later used here + +error[E0502]: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable + --> $DIR/arrays.rs:58:20 + | +LL | let mut c = || { + | -- mutable borrow occurs here +LL | arr[1] += 10; + | --- first borrow occurs due to use of `arr` in closure +... +LL | println!("{}", arr[3]); + | ^^^^^^ immutable borrow occurs here +... +LL | c(); + | - mutable borrow later used here + +error[E0502]: cannot borrow `arr` as immutable because it is also borrowed as mutable + --> $DIR/arrays.rs:74:24 + | +LL | let mut c = || { + | -- mutable borrow occurs here +LL | arr[1] += 10; + | --- first borrow occurs due to use of `arr` in closure +... +LL | println!("{:#?}", &arr[3..2]); + | ^^^ immutable borrow occurs here +... +LL | c(); + | - mutable borrow later used here + +error: aborting due to 7 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0502, E0503, E0506. +For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs new file mode 100644 index 0000000000000..15be1d8c7220d --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs @@ -0,0 +1,65 @@ +// Test borrow checker when we precise capture when using boxes + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +struct MetaData { x: String, name: String } +struct Data { m: MetaData } +struct BoxedData(Box); +struct EvenMoreBoxedData(Box); + +// Check diagnostics when the same path is mutated both inside and outside the closure +fn box_1() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let mut e = EvenMoreBoxedData(Box::new(b)); + + let mut c = || { + e.0.0.m.x = format!("not-x"); + }; + + e.0.0.m.x = format!("not-x"); + //~^ ERROR: cannot assign to `e.0.0.m.x` because it is borrowed + c(); +} + +// Check diagnostics when a path is mutated inside a closure while attempting to read it outside +// the closure. +fn box_2() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let mut e = EvenMoreBoxedData(Box::new(b)); + + let mut c = || { + e.0.0.m.x = format!("not-x"); + }; + + println!("{}", e.0.0.m.x); + //~^ ERROR: cannot borrow `e.0.0.m.x` as immutable because it is also borrowed as mutable + c(); +} + +// Check diagnostics when a path is read inside a closure while attempting to mutate it outside +// the closure. +fn box_3() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let mut e = EvenMoreBoxedData(Box::new(b)); + + let c = || { + println!("{}", e.0.0.m.x); + }; + + e.0.0.m.x = format!("not-x"); + //~^ ERROR: cannot assign to `e.0.0.m.x` because it is borrowed + c(); +} + +fn main() { + box_1(); + box_2(); + box_3(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr new file mode 100644 index 0000000000000..17a9332fb3e6c --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr @@ -0,0 +1,55 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/box.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed + --> $DIR/box.rs:22:5 + | +LL | let mut c = || { + | -- borrow of `e.0.0.m.x` occurs here +LL | e.0.0.m.x = format!("not-x"); + | - borrow occurs due to use in closure +... +LL | e.0.0.m.x = format!("not-x"); + | ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here +LL | +LL | c(); + | - borrow later used here + +error[E0502]: cannot borrow `e.0.0.m.x` as immutable because it is also borrowed as mutable + --> $DIR/box.rs:39:20 + | +LL | let mut c = || { + | -- mutable borrow occurs here +LL | e.0.0.m.x = format!("not-x"); + | - first borrow occurs due to use of `e.0.0.m.x` in closure +... +LL | println!("{}", e.0.0.m.x); + | ^^^^^^^^^ immutable borrow occurs here +LL | +LL | c(); + | - mutable borrow later used here + +error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed + --> $DIR/box.rs:56:5 + | +LL | let c = || { + | -- borrow of `e.0.0.m.x` occurs here +LL | println!("{}", e.0.0.m.x); + | - borrow occurs due to use in closure +... +LL | e.0.0.m.x = format!("not-x"); + | ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here +LL | +LL | c(); + | - borrow later used here + +error: aborting due to 3 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0502, E0506. +For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs new file mode 100644 index 0000000000000..39b04c833e384 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs @@ -0,0 +1,28 @@ +// Test that when a borrow checker diagnostics are emitted, it's as precise +// as the capture by the closure. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +#![allow(unused)] + +struct Point { + x: i32, + y: i32, +} +struct Wrapper { + p: Point, +} + +fn main() { + let mut w = Wrapper { p: Point { x: 10, y: 10 } }; + + let mut c = || { + w.p.x += 20; + }; + + let py = &mut w.p.x; + //~^ ERROR: cannot borrow `w.p.x` as mutable more than once at a time + c(); + + *py = 20 +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr new file mode 100644 index 0000000000000..e5a396c4e98ae --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr @@ -0,0 +1,26 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/multilevel-path.rs:4:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0499]: cannot borrow `w.p.x` as mutable more than once at a time + --> $DIR/multilevel-path.rs:23:14 + | +LL | let mut c = || { + | -- first mutable borrow occurs here +LL | w.p.x += 20; + | - first borrow occurs due to use of `w.p.x` in closure +... +LL | let py = &mut w.p.x; + | ^^^^^^^^^^ second mutable borrow occurs here +LL | +LL | c(); + | - first borrow later used here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs new file mode 100644 index 0000000000000..e78d8715e4893 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs @@ -0,0 +1,26 @@ +// Test that borrow checker error is accurate and that min capture pass of the +// closure analysis is working as expected. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} + +fn main() { + let mut p = Point { x: 10, y: 20 }; + + // `p` is captured via mutable borrow. + let mut c = || { + p.x += 10; + println!("{:?}", p); + }; + + + println!("{:?}", p); + //~^ ERROR: cannot borrow `p` as immutable because it is also borrowed as mutable + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr new file mode 100644 index 0000000000000..45a61cd98b101 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr @@ -0,0 +1,26 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/simple-struct-min-capture.rs:4:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable + --> $DIR/simple-struct-min-capture.rs:23:22 + | +LL | let mut c = || { + | -- mutable borrow occurs here +LL | p.x += 10; + | - first borrow occurs due to use of `p` in closure +... +LL | println!("{:?}", p); + | ^ immutable borrow occurs here +LL | +LL | c(); + | - mutable borrow later used here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/box.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/box.rs new file mode 100644 index 0000000000000..3a66399d02899 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/box.rs @@ -0,0 +1,97 @@ +// run-pass + +// Test precise capture when using boxes + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 + + +struct MetaData { x: String, name: String } +struct Data { m: MetaData } +struct BoxedData(Box); +struct EvenMoreBoxedData(Box); + +// Mutate disjoint paths, one inside one outside the closure +fn box_1() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let mut e = EvenMoreBoxedData(Box::new(b)); + + let mut c = || { + e.0.0.m.x = format!("not-x"); + }; + + e.0.0.m.name = format!("not-name"); + c(); +} + +// Mutate a path inside the closure and read a disjoint path outside the closure +fn box_2() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let mut e = EvenMoreBoxedData(Box::new(b)); + + let mut c = || { + e.0.0.m.x = format!("not-x"); + }; + + println!("{}", e.0.0.m.name); + c(); +} + +// Read a path inside the closure and mutate a disjoint path outside the closure +fn box_3() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let mut e = EvenMoreBoxedData(Box::new(b)); + + let c = || { + println!("{}", e.0.0.m.name); + }; + + e.0.0.m.x = format!("not-x"); + c(); +} + +// Read disjoint paths, one inside the closure and one outside the closure. +fn box_4() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let e = EvenMoreBoxedData(Box::new(b)); + + let c = || { + println!("{}", e.0.0.m.name); + }; + + println!("{}", e.0.0.m.x); + c(); +} + +// Read the same path, once inside the closure and once outside the closure. +fn box_5() { + let m = MetaData { x: format!("x"), name: format!("name") }; + let d = Data { m }; + let b = BoxedData(Box::new(d)); + let e = EvenMoreBoxedData(Box::new(b)); + + let c = || { + println!("{}", e.0.0.m.name); + }; + + println!("{}", e.0.0.m.name); + c(); +} + +fn main() { + box_1(); + box_2(); + box_3(); + box_4(); + box_5(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/box.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/box.stderr new file mode 100644 index 0000000000000..9883c01b946c9 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/box.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/box.rs:5:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs new file mode 100644 index 0000000000000..2c359519b769b --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs @@ -0,0 +1,28 @@ +// run-pass + +// Test that we can immutably borrow field of an instance of a structure from within a closure, +// while having a mutable borrow to another field of the same instance outside the closure. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 + +struct Point { + x: i32, + y: i32, +} + +fn main() { + let mut p = Point { x: 10, y: 10 }; + + let c = || { + println!("{}", p.x); + }; + + // `c` should only capture `p.x`, therefore mutating `p.y` is allowed. + let py = &mut p.y; + + c(); + *py = 20; +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.stderr new file mode 100644 index 0000000000000..9b0dea770fba2 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/capture-disjoint-field-struct.rs:6:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs new file mode 100644 index 0000000000000..2c6679feabe46 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs @@ -0,0 +1,23 @@ +// run-pass + +// Test that we can mutate an element of a tuple from within a closure +// while immutably borrowing another element of the same tuple outside the closure. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![feature(rustc_attrs)] + +fn main() { + let mut t = (10, 10); + + let mut c = || { + let t1 = &mut t.1; + *t1 = 20; + }; + + // Test that `c` only captures t.1, therefore reading t.0 is allowed. + println!("{}", t.0); + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.stderr new file mode 100644 index 0000000000000..28d0915395279 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/capture-disjoint-field-tuple-mut.rs:6:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs new file mode 100644 index 0000000000000..52f5cef9f01c6 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs @@ -0,0 +1,24 @@ +// run-pass + +// Test that we can immutably borrow an element of a tuple from within a closure, +// while having a mutable borrow to another element of the same tuple outside the closure. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![feature(rustc_attrs)] + +fn main() { + let mut t = (10, 10); + + let c = || { + println!("{}", t.0); + }; + + // `c` only captures t.0, therefore mutating t.1 is allowed. + let t1 = &mut t.1; + + c(); + *t1 = 20; +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.stderr new file mode 100644 index 0000000000000..4fb37f85f88b5 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/capture-disjoint-field-tuple.rs:6:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs new file mode 100644 index 0000000000000..3f8e197b7837d --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs @@ -0,0 +1,27 @@ +// run-pass + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 + +// Tests that if a closure uses indivual fields of the same object +// then that case is handled properly. + +#![allow(unused)] + +struct Struct { + x: i32, + y: i32, + s: String, +} + +fn main() { + let mut s = Struct { x: 10, y: 10, s: String::new() }; + + let mut c = { + s.x += 10; + s.y += 42; + s.s = String::from("new"); + }; +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.stderr new file mode 100644 index 0000000000000..bba90f8917acc --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/disjoint-capture-in-same-closure.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs new file mode 100644 index 0000000000000..8c12593430ef0 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs @@ -0,0 +1,41 @@ +// run-pass + +// Test disjoint capture within an impl block + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 + +struct Filter { + div: i32, +} +impl Filter { + fn allowed(&self, x: i32) -> bool { + x % self.div == 1 + } +} + +struct Data { + filter: Filter, + list: Vec, +} +impl Data { + fn update(&mut self) { + // The closure passed to filter only captures self.filter, + // therefore mutating self.list is allowed. + self.list.retain( + |v| self.filter.allowed(*v), + ); + } +} + +fn main() { + let mut d = Data { filter: Filter { div: 3 }, list: Vec::new() }; + + for i in 1..10 { + d.list.push(i); + } + + d.update(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.stderr new file mode 100644 index 0000000000000..6930e18992ae2 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/filter-on-struct-member.rs:5:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs new file mode 100644 index 0000000000000..142c156bd56e7 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs @@ -0,0 +1,36 @@ +// run-pass + +// Test that closures can catpure paths that are more precise than just one level +// from the root variable. +// +// If the closures can handle such precison we should be able to mutate one path in the closure +// while being able to mutate another path outside the closure, where the two paths are disjoint +// after applying two projections on the root variable. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![allow(unused)] + +struct Point { + x: i32, + y: i32, +} +struct Wrapper { + p: Point, +} + +fn main() { + let mut w = Wrapper { p: Point { x: 10, y: 10 } }; + + let mut c = || { + w.p.x += 20; + }; + + // `c` only captures `w.p.x`, therefore it's safe to mutate `w.p.y`. + let py = &mut w.p.y; + c(); + + *py = 20 +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.stderr new file mode 100644 index 0000000000000..94b877522f4ae --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/multilevel-path-1.rs:10:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs new file mode 100644 index 0000000000000..d8f7d55d5aa7b --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs @@ -0,0 +1,34 @@ +// run-pass + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![allow(unused)] + +// If the closures can handle such precison we should be able to read one path in the closure +// while being able mutate another path outside the closure, where the two paths are disjoint +// after applying two projections on the root variable. + + +struct Point { + x: i32, + y: i32, +} +struct Wrapper { + p: Point, +} + +fn main() { + let mut w = Wrapper { p: Point { x: 10, y: 10 } }; + + let c = || { + println!("{}", w.p.x); + }; + + // `c` only captures `w.p.x`, therefore it's safe to mutate `w.p.y`. + let py = &mut w.p.y; + c(); + + *py = 20 +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.stderr new file mode 100644 index 0000000000000..100a0e167c581 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/multilevel-path-2.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs new file mode 100644 index 0000000000000..fc3d48ec45810 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs @@ -0,0 +1,31 @@ +// run-pass + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![allow(unused)] + +// Test that when `capture_disjoint_fields` is enabled we can read a path +// both inside and outside the closure at the same time. + +struct Point { + x: i32, + y: i32, +} +struct Wrapper { + p: Point, +} + +fn main() { + let mut w = Wrapper { p: Point { x: 10, y: 10 } }; + + let c = || { + println!("{}", w.p.x); + }; + + let px = &w.p.x; + c(); + + println!("{}", px); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.stderr new file mode 100644 index 0000000000000..cf5be6a00e9a4 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/multilevel-path-3.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs new file mode 100644 index 0000000000000..238580929ef11 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs @@ -0,0 +1,40 @@ +// run-pass + +// Test whether if we can do precise capture when using nested clsoure. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 + +struct Point { + x: i32, + y: i32, +} + +fn main() { + let mut p = Point { x: 5, y: 20 }; + + // c1 should capture `p.x` via immutable borrow and + // `p.y` via mutable borrow. + let mut c1 = || { + println!("{}", p.x); + + let incr = 10; + + let mut c2 = || p.y += incr; + c2(); + + println!("{}", p.y); + }; + + c1(); + + // This should not throw an error because `p.x` is borrowed via Immutable borrow, + // and multiple immutable borrow of the same place are allowed. + let px = &p.x; + + println!("{}", px); + + c1(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.stderr new file mode 100644 index 0000000000000..293aa82ce9fea --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/nested-closure.rs:5:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/const-generics/const-argument-if-length.full.stderr b/src/test/ui/const-generics/const-argument-if-length.full.stderr index 9b1c1be1aa09b..4d627f05adc06 100644 --- a/src/test/ui/const-generics/const-argument-if-length.full.stderr +++ b/src/test/ui/const-generics/const-argument-if-length.full.stderr @@ -11,12 +11,6 @@ LL | if std::mem::size_of::() == 0 { LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` -error[E0080]: evaluation of constant value failed - --> $DIR/const-argument-if-length.rs:19:15 - | -LL | pad: [u8; is_zst::()], - | ^^^^^^^^^^^^^ referenced constant has errors - error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/const-argument-if-length.rs:17:12 | @@ -36,7 +30,6 @@ help: the `Box` type always has a statically known size and allocates its conten LL | value: Box, | ^^^^ ^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0080, E0277. -For more information about an error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/const-argument-if-length.rs b/src/test/ui/const-generics/const-argument-if-length.rs index a8bffd17b912c..8090738312418 100644 --- a/src/test/ui/const-generics/const-argument-if-length.rs +++ b/src/test/ui/const-generics/const-argument-if-length.rs @@ -18,7 +18,6 @@ pub struct AtLeastByte { //~^ ERROR the size for values of type `T` cannot be known at compilation time pad: [u8; is_zst::()], //[min]~^ ERROR generic parameters may not be used in const operations - //[full]~^^ ERROR evaluation of constant value failed } fn main() {} diff --git a/src/test/ui/consts/const-eval/erroneous-const.rs b/src/test/ui/consts/const-eval/erroneous-const.rs index 3df491bf229ff..16bf1adf7db3e 100644 --- a/src/test/ui/consts/const-eval/erroneous-const.rs +++ b/src/test/ui/consts/const-eval/erroneous-const.rs @@ -9,11 +9,11 @@ impl PrintName { const fn no_codegen() { if false { - let _ = PrintName::::VOID; //~ERROR evaluation of constant value failed + let _ = PrintName::::VOID; //~ERROR could not evaluate static initializer } } -pub static FOO: () = no_codegen::(); //~ERROR could not evaluate static initializer +pub static FOO: () = no_codegen::(); fn main() { FOO diff --git a/src/test/ui/consts/const-eval/erroneous-const.stderr b/src/test/ui/consts/const-eval/erroneous-const.stderr index 7087a6f668c82..040cc3fcf798d 100644 --- a/src/test/ui/consts/const-eval/erroneous-const.stderr +++ b/src/test/ui/consts/const-eval/erroneous-const.stderr @@ -24,18 +24,18 @@ note: the lint level is defined here LL | #![warn(const_err, unconditional_panic)] | ^^^^^^^^^ -error[E0080]: evaluation of constant value failed +error[E0080]: could not evaluate static initializer --> $DIR/erroneous-const.rs:12:17 | LL | let _ = PrintName::::VOID; - | ^^^^^^^^^^^^^^^^^^^^ referenced constant has errors - -error[E0080]: could not evaluate static initializer - --> $DIR/erroneous-const.rs:16:22 - | + | ^^^^^^^^^^^^^^^^^^^^ + | | + | referenced constant has errors + | inside `no_codegen::` at $DIR/erroneous-const.rs:12:17 +... LL | pub static FOO: () = no_codegen::(); - | ^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | ------------------- inside `FOO` at $DIR/erroneous-const.rs:16:22 -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs new file mode 100644 index 0000000000000..0d809ca9a622b --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs @@ -0,0 +1,17 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: i32 = foo(); +const fn foo() -> i32 { + unsafe { + let _ = intrinsics::const_allocate(4, 3) as * mut i32; + //~^ error: any use of this value will cause an error [const_err] + } + 1 + +} + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr new file mode 100644 index 0000000000000..41c1b977269a3 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr @@ -0,0 +1,17 @@ +error: any use of this value will cause an error + --> $DIR/alloc_intrinsic_errors.rs:10:17 + | +LL | const FOO: i32 = foo(); + | ----------------------- +... +LL | let _ = intrinsics::const_allocate(4, 3) as * mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | align has to be a power of 2, `3` is not a power of 2 + | inside `foo` at $DIR/alloc_intrinsic_errors.rs:10:17 + | inside `FOO` at $DIR/alloc_intrinsic_errors.rs:7:18 + | + = note: `#[deny(const_err)]` on by default + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs new file mode 100644 index 0000000000000..de7fb65f6858f --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -0,0 +1,20 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: &i32 = foo(); + +const fn foo() -> &'static i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as * mut i32; + *i = 20; + i + }; + unsafe { &*t } +} +fn main() { + assert_eq!(*FOO, 20) +} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs new file mode 100644 index 0000000000000..e6ef9974aa8eb --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs @@ -0,0 +1,19 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: *const i32 = foo(); +//~^ ERROR untyped pointers are not allowed in constant + +const fn foo() -> &'static i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as * mut i32; + *i = 20; + i + }; + unsafe { &*t } +} +fn main() { +} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr new file mode 100644 index 0000000000000..08679350d6d54 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr @@ -0,0 +1,8 @@ +error: untyped pointers are not allowed in constant + --> $DIR/alloc_intrinsic_nontransient_fail.rs:7:1 + | +LL | const FOO: *const i32 = foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs new file mode 100644 index 0000000000000..c55cd32d26425 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs @@ -0,0 +1,20 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: i32 = foo(); + +const fn foo() -> i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as * mut i32; + *i = 20; + i + }; + unsafe { *t } +} +fn main() { + assert_eq!(FOO, 20); +} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs new file mode 100644 index 0000000000000..998b6cef84a72 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs @@ -0,0 +1,10 @@ +// compile-test +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; +//~^ error: it is undefined behavior to use this value +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr new file mode 100644 index 0000000000000..866f877f54d43 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr @@ -0,0 +1,11 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/alloc_intrinsic_uninit.rs:8:1 + | +LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at ., but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs new file mode 100644 index 0000000000000..625f7670bcd63 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs @@ -0,0 +1,10 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32}; +//~^ error: untyped pointers are not allowed in constant + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr new file mode 100644 index 0000000000000..ee84f8e54f344 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr @@ -0,0 +1,8 @@ +error: untyped pointers are not allowed in constant + --> $DIR/alloc_intrinsic_untyped.rs:7:1 + | +LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/unwind-abort.rs b/src/test/ui/consts/const-eval/unwind-abort.rs index b8b95dea1e770..2dc8e14bed545 100644 --- a/src/test/ui/consts/const-eval/unwind-abort.rs +++ b/src/test/ui/consts/const-eval/unwind-abort.rs @@ -2,10 +2,10 @@ #[unwind(aborts)] const fn foo() { - panic!() //~ evaluation of constant value failed + panic!() //~ ERROR any use of this value will cause an error [const_err] } -const _: () = foo(); //~ any use of this value will cause an error +const _: () = foo(); // Ensure that the CTFE engine handles calls to `#[unwind(aborts)]` gracefully fn main() { diff --git a/src/test/ui/consts/const-eval/unwind-abort.stderr b/src/test/ui/consts/const-eval/unwind-abort.stderr index 084beb19eb934..eee1a35a0dc88 100644 --- a/src/test/ui/consts/const-eval/unwind-abort.stderr +++ b/src/test/ui/consts/const-eval/unwind-abort.stderr @@ -1,21 +1,18 @@ -error[E0080]: evaluation of constant value failed +error: any use of this value will cause an error --> $DIR/unwind-abort.rs:5:5 | LL | panic!() - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5 - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: any use of this value will cause an error - --> $DIR/unwind-abort.rs:8:15 - | + | ^^^^^^^^ + | | + | the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5 + | inside `foo` at $SRC_DIR/std/src/macros.rs:LL:COL + | inside `_` at $DIR/unwind-abort.rs:8:15 +... LL | const _: () = foo(); - | --------------^^^^^- - | | - | referenced constant has errors + | -------------------- | = note: `#[deny(const_err)]` on by default + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index fdbe3f0c59294..129457ebdf929 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -14,11 +14,6 @@ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`.. | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `std::mem::size_of`... - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL - | -LL | pub const fn size_of() -> usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `[u8; _]`... = note: ...which again requires simplifying constant for the type system `Foo::bytes::{constant#0}`, completing the cycle diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.rs b/src/test/ui/consts/uninhabited-const-issue-61744.rs index 15436f9c1b2cf..2f4b7578d1c32 100644 --- a/src/test/ui/consts/uninhabited-const-issue-61744.rs +++ b/src/test/ui/consts/uninhabited-const-issue-61744.rs @@ -1,15 +1,15 @@ // build-fail pub const unsafe fn fake_type() -> T { - hint_unreachable() + hint_unreachable() //~ ERROR any use of this value will cause an error [const_err] } pub const unsafe fn hint_unreachable() -> ! { - fake_type() //~ ERROR evaluation of constant value failed + fake_type() } trait Const { - const CONSTANT: i32 = unsafe { fake_type() }; //~ ERROR any use of this value will cause an err + const CONSTANT: i32 = unsafe { fake_type() }; } impl Const for T {} diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.stderr b/src/test/ui/consts/uninhabited-const-issue-61744.stderr index 024f9782d4a67..1fb5ac11df0f0 100644 --- a/src/test/ui/consts/uninhabited-const-issue-61744.stderr +++ b/src/test/ui/consts/uninhabited-const-issue-61744.stderr @@ -1,150 +1,141 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/uninhabited-const-issue-61744.rs:8:5 +error: any use of this value will cause an error + --> $DIR/uninhabited-const-issue-61744.rs:4:5 | LL | hint_unreachable() - | ------------------ + | ^^^^^^^^^^^^^^^^^^ | | + | reached the configured maximum number of stack frames | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `::CONSTANT` at $DIR/uninhabited-const-issue-61744.rs:12:36 ... -LL | fake_type() - | ^^^^^^^^^^^ - | | - | reached the configured maximum number of stack frames - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - -error: any use of this value will cause an error - --> $DIR/uninhabited-const-issue-61744.rs:12:36 - | LL | const CONSTANT: i32 = unsafe { fake_type() }; - | -------------------------------^^^^^^^^^^^--- - | | - | referenced constant has errors + | --------------------------------------------- | = note: `#[deny(const_err)]` on by default @@ -154,6 +145,6 @@ error[E0080]: erroneous constant used LL | dbg!(i32::CONSTANT); | ^^^^^^^^^^^^^ referenced constant has errors -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/cycle-projection-based-on-where-clause.rs b/src/test/ui/cycle-projection-based-on-where-clause.rs new file mode 100644 index 0000000000000..d3609acfdff63 --- /dev/null +++ b/src/test/ui/cycle-projection-based-on-where-clause.rs @@ -0,0 +1,24 @@ +// Example cycle where a bound on `T` uses a shorthand for `T`. This +// creates a cycle because we have to know the bounds on `T` to figure +// out what trait defines `Item`, but we can't know the bounds on `T` +// without knowing how to handle `T::Item`. +// +// Note that in the future cases like this could perhaps become legal, +// if we got more fine-grained about our cycle detection or changed +// how we handle `T::Item` resolution. + +use std::ops::Add; + +// Preamble. +trait Trait { type Item; } + +struct A + where T : Trait, + T : Add + //~^ ERROR cycle detected +{ + data: T +} + +fn main() { +} diff --git a/src/test/ui/cycle-projection-based-on-where-clause.stderr b/src/test/ui/cycle-projection-based-on-where-clause.stderr new file mode 100644 index 0000000000000..2c337cc6bf903 --- /dev/null +++ b/src/test/ui/cycle-projection-based-on-where-clause.stderr @@ -0,0 +1,16 @@ +error[E0391]: cycle detected when computing the bounds for type parameter `T` + --> $DIR/cycle-projection-based-on-where-clause.rs:17:19 + | +LL | T : Add + | ^^^^^^^ + | + = note: ...which again requires computing the bounds for type parameter `T`, completing the cycle +note: cycle used when computing explicit predicates of `A` + --> $DIR/cycle-projection-based-on-where-clause.rs:17:19 + | +LL | T : Add + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr index ee54b2fd151d7..8aa3ac8abf52c 100644 --- a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr @@ -1,15 +1,10 @@ -error[E0391]: cycle detected when computing the super predicates of `Chromosome` - --> $DIR/cycle-trait-supertrait-direct.rs:3:1 - | -LL | trait Chromosome: Chromosome { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires computing the super traits of `Chromosome`... +error[E0391]: cycle detected when computing the supertraits of `Chromosome` --> $DIR/cycle-trait-supertrait-direct.rs:3:19 | LL | trait Chromosome: Chromosome { | ^^^^^^^^^^ - = note: ...which again requires computing the super predicates of `Chromosome`, completing the cycle + | + = note: ...which again requires computing the supertraits of `Chromosome`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-supertrait-direct.rs:3:1 | diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr index 0a2284e0efbca..9740f43a4ba97 100644 --- a/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr @@ -1,26 +1,16 @@ -error[E0391]: cycle detected when computing the super predicates of `B` - --> $DIR/cycle-trait-supertrait-indirect.rs:7:1 - | -LL | trait B: C { - | ^^^^^^^^^^ - | -note: ...which requires computing the super traits of `B`... +error[E0391]: cycle detected when computing the supertraits of `B` --> $DIR/cycle-trait-supertrait-indirect.rs:7:10 | LL | trait B: C { | ^ -note: ...which requires computing the super predicates of `C`... - --> $DIR/cycle-trait-supertrait-indirect.rs:11:1 | -LL | trait C: B { } - | ^^^^^^^^^^ -note: ...which requires computing the super traits of `C`... +note: ...which requires computing the supertraits of `C`... --> $DIR/cycle-trait-supertrait-indirect.rs:11:10 | LL | trait C: B { } | ^ - = note: ...which again requires computing the super predicates of `B`, completing the cycle -note: cycle used when computing the super traits of `A` + = note: ...which again requires computing the supertraits of `B`, completing the cycle +note: cycle used when computing the supertraits of `A` --> $DIR/cycle-trait-supertrait-indirect.rs:4:10 | LL | trait A: B { diff --git a/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr b/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr index d05d6d120b084..26c24d7432c48 100644 --- a/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr +++ b/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr @@ -47,46 +47,19 @@ error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:67:10 | LL | for x, _barr_body in women.iter().map(|woman| woman.allosomes.clone()) { - | ^ - | -help: try adding parentheses to match on a tuple... - | -LL | for (x, _barr_body) in women.iter().map(|woman| woman.allosomes.clone()) { - | ^^^^^^^^^^^^^^^ -help: ...or a vertical bar to match on multiple alternatives - | -LL | for x | _barr_body in women.iter().map(|woman| woman.allosomes.clone()) { - | ^^^^^^^^^^^^^^ + | -^----------- help: try adding parentheses to match on a tuple: `(x, _barr_body)` error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:75:10 | LL | for x, y @ Allosome::Y(_) in men.iter().map(|man| man.allosomes.clone()) { - | ^ - | -help: try adding parentheses to match on a tuple... - | -LL | for (x, y @ Allosome::Y(_)) in men.iter().map(|man| man.allosomes.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ -help: ...or a vertical bar to match on multiple alternatives - | -LL | for x | y @ Allosome::Y(_) in men.iter().map(|man| man.allosomes.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^ + | -^------------------- help: try adding parentheses to match on a tuple: `(x, y @ Allosome::Y(_))` error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:84:14 | LL | let women, men: (Vec, Vec) = genomes.iter().cloned() - | ^ - | -help: try adding parentheses to match on a tuple... - | -LL | let (women, men): (Vec, Vec) = genomes.iter().cloned() - | ^^^^^^^^^^^^ -help: ...or a vertical bar to match on multiple alternatives - | -LL | let women | men: (Vec, Vec) = genomes.iter().cloned() - | ^^^^^^^^^^^ + | -----^---- help: try adding parentheses to match on a tuple: `(women, men)` error: aborting due to 6 previous errors diff --git a/src/test/ui/doc-alias-crate-level.rs b/src/test/ui/doc-alias-crate-level.rs index b1b17f2de8adf..9b596ece5b55a 100644 --- a/src/test/ui/doc-alias-crate-level.rs +++ b/src/test/ui/doc-alias-crate-level.rs @@ -4,4 +4,7 @@ #![crate_type = "lib"] -#![doc(alias = "shouldn't work!")] //~ ERROR +#![doc(alias = "not working!")] //~ ERROR + +#[doc(alias = "shouldn't work!")] //~ ERROR +pub struct Foo; diff --git a/src/test/ui/doc-alias-crate-level.stderr b/src/test/ui/doc-alias-crate-level.stderr index 32b42cf9be766..b6437fad5d05a 100644 --- a/src/test/ui/doc-alias-crate-level.stderr +++ b/src/test/ui/doc-alias-crate-level.stderr @@ -1,8 +1,14 @@ error: '\'' character isn't allowed in `#[doc(alias = "...")]` - --> $DIR/doc-alias-crate-level.rs:7:16 + --> $DIR/doc-alias-crate-level.rs:9:15 | -LL | #![doc(alias = "shouldn't work!")] - | ^^^^^^^^^^^^^^^^^ +LL | #[doc(alias = "shouldn't work!")] + | ^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: `#![doc(alias = "...")]` isn't allowed as a crate level attribute + --> $DIR/doc-alias-crate-level.rs:7:8 + | +LL | #![doc(alias = "not working!")] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/doc_keyword.rs b/src/test/ui/doc_keyword.rs new file mode 100644 index 0000000000000..4c72e7e96842c --- /dev/null +++ b/src/test/ui/doc_keyword.rs @@ -0,0 +1,12 @@ +#![crate_type = "lib"] +#![feature(doc_keyword)] + +#![doc(keyword = "hello")] //~ ERROR + +#[doc(keyword = "hell")] //~ ERROR +mod foo { + fn hell() {} +} + +#[doc(keyword = "hall")] //~ ERROR +fn foo() {} diff --git a/src/test/ui/doc_keyword.stderr b/src/test/ui/doc_keyword.stderr new file mode 100644 index 0000000000000..d72a876163eb3 --- /dev/null +++ b/src/test/ui/doc_keyword.stderr @@ -0,0 +1,20 @@ +error: `#[doc(keyword = "...")]` can only be used on empty modules + --> $DIR/doc_keyword.rs:6:7 + | +LL | #[doc(keyword = "hell")] + | ^^^^^^^^^^^^^^^^ + +error: `#[doc(keyword = "...")]` can only be used on modules + --> $DIR/doc_keyword.rs:11:7 + | +LL | #[doc(keyword = "hall")] + | ^^^^^^^^^^^^^^^^ + +error: `#![doc(keyword = "...")]` isn't allowed as a crate level attribute + --> $DIR/doc_keyword.rs:4:8 + | +LL | #![doc(keyword = "hello")] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs index c4f7c3786168b..a952fe8e76e81 100644 --- a/src/test/ui/drop/dynamic-drop-async.rs +++ b/src/test/ui/drop/dynamic-drop-async.rs @@ -43,6 +43,7 @@ impl Future for Defer { /// The `failing_op`-th operation will panic. struct Allocator { data: RefCell>, + name: &'static str, failing_op: usize, cur_ops: Cell, } @@ -54,23 +55,28 @@ impl Drop for Allocator { fn drop(&mut self) { let data = self.data.borrow(); if data.iter().any(|d| *d) { - panic!("missing free: {:?}", data); + panic!("missing free in {:?}: {:?}", self.name, data); } } } impl Allocator { - fn new(failing_op: usize) -> Self { - Allocator { failing_op, cur_ops: Cell::new(0), data: RefCell::new(vec![]) } + fn new(failing_op: usize, name: &'static str) -> Self { + Allocator { + failing_op, + name, + cur_ops: Cell::new(0), + data: RefCell::new(vec![]), + } } - fn alloc(&self) -> impl Future> + '_ { + fn alloc(self: &Rc) -> impl Future + 'static { self.fallible_operation(); let mut data = self.data.borrow_mut(); let addr = data.len(); data.push(true); - Defer { ready: false, value: Some(Ptr(addr, self)) } + Defer { ready: false, value: Some(Ptr(addr, self.clone())) } } fn fallible_operation(&self) { self.cur_ops.set(self.cur_ops.get() + 1); @@ -83,11 +89,11 @@ impl Allocator { // Type that tracks whether it was dropped and can panic when it's created or // destroyed. -struct Ptr<'a>(usize, &'a Allocator); -impl<'a> Drop for Ptr<'a> { +struct Ptr(usize, Rc); +impl Drop for Ptr { fn drop(&mut self) { match self.1.data.borrow_mut()[self.0] { - false => panic!("double free at index {:?}", self.0), + false => panic!("double free in {:?} at index {:?}", self.1.name, self.0), ref mut d => *d = false, } @@ -111,7 +117,7 @@ async fn dynamic_drop(a: Rc, c: bool) { }; } -struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>); +struct TwoPtrs(Ptr, Ptr); async fn struct_dynamic_drop(a: Rc, c0: bool, c1: bool, c: bool) { for i in 0..2 { let x; @@ -232,21 +238,62 @@ async fn move_ref_pattern(a: Rc) { a.alloc().await; } -fn run_test(cx: &mut Context<'_>, ref f: F) +async fn panic_after_return(a: Rc, c: bool) -> (Ptr,) { + a.alloc().await; + let p = a.alloc().await; + if c { + a.alloc().await; + let q = a.alloc().await; + // We use a return type that isn't used anywhere else to make sure that + // the return place doesn't incorrectly end up in the generator state. + return (a.alloc().await,); + } + (a.alloc().await,) +} + + +async fn panic_after_init_by_loop(a: Rc) { + a.alloc().await; + let p = a.alloc().await; + let q = loop { + a.alloc().await; + let r = a.alloc().await; + break a.alloc().await; + }; +} + +async fn panic_after_init_by_match_with_bindings_and_guard(a: Rc, b: bool) { + a.alloc().await; + let p = a.alloc().await; + let q = match a.alloc().await { + ref _x if b => { + a.alloc().await; + let r = a.alloc().await; + a.alloc().await + } + _x => { + a.alloc().await; + let r = a.alloc().await; + a.alloc().await + }, + }; +} + +fn run_test(cx: &mut Context<'_>, ref f: F, name: &'static str) where F: Fn(Rc) -> G, - G: Future, + G: Future, { for polls in 0.. { // Run without any panics to find which operations happen after the // penultimate `poll`. - let first_alloc = Rc::new(Allocator::new(usize::MAX)); + let first_alloc = Rc::new(Allocator::new(usize::MAX, name)); let mut fut = Box::pin(f(first_alloc.clone())); let mut ops_before_last_poll = 0; let mut completed = false; for _ in 0..polls { ops_before_last_poll = first_alloc.cur_ops.get(); - if let Poll::Ready(()) = fut.as_mut().poll(cx) { + if let Poll::Ready(_) = fut.as_mut().poll(cx) { completed = true; } } @@ -255,7 +302,7 @@ where // Start at `ops_before_last_poll` so that we will always be able to // `poll` the expected number of times. for failing_op in ops_before_last_poll..first_alloc.cur_ops.get() { - let alloc = Rc::new(Allocator::new(failing_op + 1)); + let alloc = Rc::new(Allocator::new(failing_op + 1, name)); let f = &f; let cx = &mut *cx; let result = panic::catch_unwind(panic::AssertUnwindSafe(move || { @@ -285,48 +332,58 @@ fn clone_waker(data: *const ()) -> RawWaker { RawWaker::new(data, &RawWakerVTable::new(clone_waker, drop, drop, drop)) } +macro_rules! run_test { + ($ctxt:expr, $e:expr) => { run_test($ctxt, $e, stringify!($e)); }; +} + fn main() { let waker = unsafe { Waker::from_raw(clone_waker(ptr::null())) }; let context = &mut Context::from_waker(&waker); - run_test(context, |a| dynamic_init(a, false)); - run_test(context, |a| dynamic_init(a, true)); - run_test(context, |a| dynamic_drop(a, false)); - run_test(context, |a| dynamic_drop(a, true)); - - run_test(context, |a| assignment(a, false, false)); - run_test(context, |a| assignment(a, false, true)); - run_test(context, |a| assignment(a, true, false)); - run_test(context, |a| assignment(a, true, true)); - - run_test(context, |a| array_simple(a)); - run_test(context, |a| vec_simple(a)); - run_test(context, |a| vec_unreachable(a)); - - run_test(context, |a| struct_dynamic_drop(a, false, false, false)); - run_test(context, |a| struct_dynamic_drop(a, false, false, true)); - run_test(context, |a| struct_dynamic_drop(a, false, true, false)); - run_test(context, |a| struct_dynamic_drop(a, false, true, true)); - run_test(context, |a| struct_dynamic_drop(a, true, false, false)); - run_test(context, |a| struct_dynamic_drop(a, true, false, true)); - run_test(context, |a| struct_dynamic_drop(a, true, true, false)); - run_test(context, |a| struct_dynamic_drop(a, true, true, true)); - - run_test(context, |a| field_assignment(a, false)); - run_test(context, |a| field_assignment(a, true)); - - run_test(context, |a| mixed_drop_and_nondrop(a)); - - run_test(context, |a| slice_pattern_one_of(a, 0)); - run_test(context, |a| slice_pattern_one_of(a, 1)); - run_test(context, |a| slice_pattern_one_of(a, 2)); - run_test(context, |a| slice_pattern_one_of(a, 3)); - - run_test(context, |a| subslice_pattern_from_end_with_drop(a, true, true)); - run_test(context, |a| subslice_pattern_from_end_with_drop(a, true, false)); - run_test(context, |a| subslice_pattern_from_end_with_drop(a, false, true)); - run_test(context, |a| subslice_pattern_from_end_with_drop(a, false, false)); - run_test(context, |a| subslice_pattern_reassign(a)); - - run_test(context, |a| move_ref_pattern(a)); + run_test!(context, |a| dynamic_init(a, false)); + run_test!(context, |a| dynamic_init(a, true)); + run_test!(context, |a| dynamic_drop(a, false)); + run_test!(context, |a| dynamic_drop(a, true)); + + run_test!(context, |a| assignment(a, false, false)); + run_test!(context, |a| assignment(a, false, true)); + run_test!(context, |a| assignment(a, true, false)); + run_test!(context, |a| assignment(a, true, true)); + + run_test!(context, |a| array_simple(a)); + run_test!(context, |a| vec_simple(a)); + run_test!(context, |a| vec_unreachable(a)); + + run_test!(context, |a| struct_dynamic_drop(a, false, false, false)); + run_test!(context, |a| struct_dynamic_drop(a, false, false, true)); + run_test!(context, |a| struct_dynamic_drop(a, false, true, false)); + run_test!(context, |a| struct_dynamic_drop(a, false, true, true)); + run_test!(context, |a| struct_dynamic_drop(a, true, false, false)); + run_test!(context, |a| struct_dynamic_drop(a, true, false, true)); + run_test!(context, |a| struct_dynamic_drop(a, true, true, false)); + run_test!(context, |a| struct_dynamic_drop(a, true, true, true)); + + run_test!(context, |a| field_assignment(a, false)); + run_test!(context, |a| field_assignment(a, true)); + + run_test!(context, |a| mixed_drop_and_nondrop(a)); + + run_test!(context, |a| slice_pattern_one_of(a, 0)); + run_test!(context, |a| slice_pattern_one_of(a, 1)); + run_test!(context, |a| slice_pattern_one_of(a, 2)); + run_test!(context, |a| slice_pattern_one_of(a, 3)); + + run_test!(context, |a| subslice_pattern_from_end_with_drop(a, true, true)); + run_test!(context, |a| subslice_pattern_from_end_with_drop(a, true, false)); + run_test!(context, |a| subslice_pattern_from_end_with_drop(a, false, true)); + run_test!(context, |a| subslice_pattern_from_end_with_drop(a, false, false)); + run_test!(context, |a| subslice_pattern_reassign(a)); + + run_test!(context, |a| move_ref_pattern(a)); + + run_test!(context, |a| panic_after_return(a, false)); + run_test!(context, |a| panic_after_return(a, true)); + run_test!(context, |a| panic_after_init_by_loop(a)); + run_test!(context, |a| panic_after_init_by_match_with_bindings_and_guard(a, false)); + run_test!(context, |a| panic_after_init_by_match_with_bindings_and_guard(a, true)); } diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index 88f557055f371..ddccee20e12a6 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -3,7 +3,6 @@ #![feature(generators, generator_trait)] #![feature(bindings_after_at)] - #![allow(unused_assignments)] #![allow(unused_variables)] @@ -17,6 +16,7 @@ struct InjectedFailure; struct Allocator { data: RefCell>, + name: &'static str, failing_op: usize, cur_ops: Cell, } @@ -28,17 +28,18 @@ impl Drop for Allocator { fn drop(&mut self) { let data = self.data.borrow(); if data.iter().any(|d| *d) { - panic!("missing free: {:?}", data); + panic!("missing free in {:?}: {:?}", self.name, data); } } } impl Allocator { - fn new(failing_op: usize) -> Self { + fn new(failing_op: usize, name: &'static str) -> Self { Allocator { failing_op: failing_op, cur_ops: Cell::new(0), - data: RefCell::new(vec![]) + data: RefCell::new(vec![]), + name, } } fn alloc(&self) -> Ptr<'_> { @@ -53,33 +54,17 @@ impl Allocator { data.push(true); Ptr(addr, self) } - // FIXME(#47949) Any use of this indicates a bug in rustc: we should never - // be leaking values in the cases here. - // - // Creates a `Ptr<'_>` and checks that the allocated value is leaked if the - // `failing_op` is in the list of exception. - fn alloc_leaked(&self, exceptions: Vec) -> Ptr<'_> { - let ptr = self.alloc(); - - if exceptions.iter().any(|operation| *operation == self.failing_op) { - let mut data = self.data.borrow_mut(); - data[ptr.0] = false; - } - ptr - } } struct Ptr<'a>(usize, &'a Allocator); impl<'a> Drop for Ptr<'a> { fn drop(&mut self) { match self.1.data.borrow_mut()[self.0] { - false => { - panic!("double free at index {:?}", self.0) - } - ref mut d => *d = false + false => panic!("double free in {:?} at index {:?}", self.1.name, self.0), + ref mut d => *d = false, } - self.1.cur_ops.set(self.1.cur_ops.get()+1); + self.1.cur_ops.set(self.1.cur_ops.get() + 1); if self.1.cur_ops.get() == self.1.failing_op { panic!(InjectedFailure); @@ -177,11 +162,7 @@ fn generator(a: &Allocator, run_count: usize) { assert!(run_count < 4); let mut gen = || { - (a.alloc(), - yield a.alloc(), - a.alloc(), - yield a.alloc() - ); + (a.alloc(), yield a.alloc(), a.alloc(), yield a.alloc()); }; for _ in 0..run_count { Pin::new(&mut gen).resume(()); @@ -205,28 +186,40 @@ fn vec_unreachable(a: &Allocator) { } fn slice_pattern_first(a: &Allocator) { - let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()]; + let [_x, ..] = [a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_middle(a: &Allocator) { - let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()]; + let [_, _x, _] = [a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_two(a: &Allocator) { - let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; + let [_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_last(a: &Allocator) { - let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; + let [.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_one_of(a: &Allocator, i: usize) { let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; let _x = match i { - 0 => { let [a, ..] = array; a } - 1 => { let [_, a, ..] = array; a } - 2 => { let [_, _, a, _] = array; a } - 3 => { let [_, _, _, a] = array; a } + 0 => { + let [a, ..] = array; + a + } + 1 => { + let [_, a, ..] = array; + a + } + 2 => { + let [_, _, a, _] = array; + a + } + 3 => { + let [_, _, _, a] = array; + a + } _ => panic!("unmatched"), }; } @@ -234,9 +227,9 @@ fn slice_pattern_one_of(a: &Allocator, i: usize) { fn subslice_pattern_from_end(a: &Allocator, arg: bool) { let a = [a.alloc(), a.alloc(), a.alloc()]; if arg { - let[.., _x, _] = a; + let [.., _x, _] = a; } else { - let[_, _y @ ..] = a; + let [_, _y @ ..] = a; } } @@ -248,45 +241,61 @@ fn subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool) { } if arg { - let[.., _x, _] = a; + let [.., _x, _] = a; } else { - let[_, _y @ ..] = a; + let [_, _y @ ..] = a; } } fn slice_pattern_reassign(a: &Allocator) { let mut ar = [a.alloc(), a.alloc()]; - let[_, _x] = ar; + let [_, _x] = ar; ar = [a.alloc(), a.alloc()]; - let[.., _y] = ar; + let [.., _y] = ar; } fn subslice_pattern_reassign(a: &Allocator) { let mut ar = [a.alloc(), a.alloc(), a.alloc()]; - let[_, _, _x] = ar; + let [_, _, _x] = ar; ar = [a.alloc(), a.alloc(), a.alloc()]; - let[_, _y @ ..] = ar; + let [_, _y @ ..] = ar; } fn index_field_mixed_ends(a: &Allocator) { let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())]; - let[(_x, _), ..] = ar; - let[(_, _y), _] = ar; - let[_, (_, _w)] = ar; - let[.., (_z, _)] = ar; + let [(_x, _), ..] = ar; + let [(_, _y), _] = ar; + let [_, (_, _w)] = ar; + let [.., (_z, _)] = ar; } fn subslice_mixed_min_lengths(a: &Allocator, c: i32) { let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())]; match c { - 0 => { let[_x, ..] = ar; } - 1 => { let[_x, _, ..] = ar; } - 2 => { let[_x, _] = ar; } - 3 => { let[(_x, _), _, ..] = ar; } - 4 => { let[.., (_x, _)] = ar; } - 5 => { let[.., (_x, _), _] = ar; } - 6 => { let [_y @ ..] = ar; } - _ => { let [_y @ .., _] = ar; } + 0 => { + let [_x, ..] = ar; + } + 1 => { + let [_x, _, ..] = ar; + } + 2 => { + let [_x, _] = ar; + } + 3 => { + let [(_x, _), _, ..] = ar; + } + 4 => { + let [.., (_x, _)] = ar; + } + 5 => { + let [.., (_x, _), _] = ar; + } + 6 => { + let [_y @ ..] = ar; + } + _ => { + let [_y @ .., _] = ar; + } } } @@ -334,87 +343,160 @@ fn move_ref_pattern(a: &Allocator) { } fn panic_after_return(a: &Allocator) -> Ptr<'_> { - // Panic in the drop of `p` or `q` can leak - let exceptions = vec![8, 9]; a.alloc(); let p = a.alloc(); { a.alloc(); let p = a.alloc(); - // FIXME (#47949) We leak values when we panic in a destructor after - // evaluating an expression with `rustc_mir::build::Builder::into`. - a.alloc_leaked(exceptions) + a.alloc() } } fn panic_after_return_expr(a: &Allocator) -> Ptr<'_> { - // Panic in the drop of `p` or `q` can leak - let exceptions = vec![8, 9]; a.alloc(); let p = a.alloc(); { a.alloc(); let q = a.alloc(); - // FIXME (#47949) - return a.alloc_leaked(exceptions); + return a.alloc(); } } fn panic_after_init(a: &Allocator) { - // Panic in the drop of `r` can leak - let exceptions = vec![8]; a.alloc(); let p = a.alloc(); let q = { a.alloc(); let r = a.alloc(); - // FIXME (#47949) - a.alloc_leaked(exceptions) + a.alloc() }; } fn panic_after_init_temp(a: &Allocator) { - // Panic in the drop of `r` can leak - let exceptions = vec![8]; a.alloc(); let p = a.alloc(); { a.alloc(); let r = a.alloc(); - // FIXME (#47949) - a.alloc_leaked(exceptions) + a.alloc() }; } fn panic_after_init_by_loop(a: &Allocator) { - // Panic in the drop of `r` can leak - let exceptions = vec![8]; a.alloc(); let p = a.alloc(); let q = loop { a.alloc(); let r = a.alloc(); - // FIXME (#47949) - break a.alloc_leaked(exceptions); + break a.alloc(); + }; +} + +fn panic_after_init_by_match(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let _ = loop { + let q = match b { + true => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + false => { + a.alloc(); + let r = a.alloc(); + break a.alloc(); + } + }; + return; + }; +} + +fn panic_after_init_by_match_with_guard(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let q = match a.alloc() { + _ if b => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + _ => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + }; +} + +fn panic_after_init_by_match_with_bindings_and_guard(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let q = match a.alloc() { + _x if b => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + _x => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + }; +} + +fn panic_after_init_by_match_with_ref_bindings_and_guard(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let q = match a.alloc() { + ref _x if b => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + ref _x => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + }; +} + +fn panic_after_init_by_break_if(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let q = loop { + let r = a.alloc(); + break if b { + let s = a.alloc(); + a.alloc() + } else { + a.alloc() + }; }; } -fn run_test(mut f: F) - where F: FnMut(&Allocator) +fn run_test(mut f: F, name: &'static str) +where + F: FnMut(&Allocator), { - let first_alloc = Allocator::new(usize::MAX); + let first_alloc = Allocator::new(usize::MAX, name); f(&first_alloc); - for failing_op in 1..first_alloc.cur_ops.get()+1 { - let alloc = Allocator::new(failing_op); + for failing_op in 1..first_alloc.cur_ops.get() + 1 { + let alloc = Allocator::new(failing_op, name); let alloc = &alloc; let f = panic::AssertUnwindSafe(&mut f); let result = panic::catch_unwind(move || { f.0(alloc); }); match result { - Ok(..) => panic!("test executed {} ops but now {}", - first_alloc.cur_ops.get(), alloc.cur_ops.get()), + Ok(..) => panic!( + "test executed {} ops but now {}", + first_alloc.cur_ops.get(), + alloc.cur_ops.get() + ), Err(e) => { if e.downcast_ref::().is_none() { panic::resume_unwind(e); @@ -424,98 +506,115 @@ fn run_test(mut f: F) } } -fn run_test_nopanic(mut f: F) - where F: FnMut(&Allocator) +fn run_test_nopanic(mut f: F, name: &'static str) +where + F: FnMut(&Allocator), { - let first_alloc = Allocator::new(usize::MAX); + let first_alloc = Allocator::new(usize::MAX, name); f(&first_alloc); } +macro_rules! run_test { + ($e:expr) => { + run_test($e, stringify!($e)); + }; +} + fn main() { - run_test(|a| dynamic_init(a, false)); - run_test(|a| dynamic_init(a, true)); - run_test(|a| dynamic_drop(a, false)); - run_test(|a| dynamic_drop(a, true)); - - run_test(|a| assignment2(a, false, false)); - run_test(|a| assignment2(a, false, true)); - run_test(|a| assignment2(a, true, false)); - run_test(|a| assignment2(a, true, true)); - - run_test(|a| assignment1(a, false)); - run_test(|a| assignment1(a, true)); - - run_test(|a| array_simple(a)); - run_test(|a| vec_simple(a)); - run_test(|a| vec_unreachable(a)); - - run_test(|a| struct_dynamic_drop(a, false, false, false)); - run_test(|a| struct_dynamic_drop(a, false, false, true)); - run_test(|a| struct_dynamic_drop(a, false, true, false)); - run_test(|a| struct_dynamic_drop(a, false, true, true)); - run_test(|a| struct_dynamic_drop(a, true, false, false)); - run_test(|a| struct_dynamic_drop(a, true, false, true)); - run_test(|a| struct_dynamic_drop(a, true, true, false)); - run_test(|a| struct_dynamic_drop(a, true, true, true)); - - run_test(|a| field_assignment(a, false)); - run_test(|a| field_assignment(a, true)); - - run_test(|a| generator(a, 0)); - run_test(|a| generator(a, 1)); - run_test(|a| generator(a, 2)); - run_test(|a| generator(a, 3)); - - run_test(|a| mixed_drop_and_nondrop(a)); - - run_test(|a| slice_pattern_first(a)); - run_test(|a| slice_pattern_middle(a)); - run_test(|a| slice_pattern_two(a)); - run_test(|a| slice_pattern_last(a)); - run_test(|a| slice_pattern_one_of(a, 0)); - run_test(|a| slice_pattern_one_of(a, 1)); - run_test(|a| slice_pattern_one_of(a, 2)); - run_test(|a| slice_pattern_one_of(a, 3)); - - run_test(|a| subslice_pattern_from_end(a, true)); - run_test(|a| subslice_pattern_from_end(a, false)); - run_test(|a| subslice_pattern_from_end_with_drop(a, true, true)); - run_test(|a| subslice_pattern_from_end_with_drop(a, true, false)); - run_test(|a| subslice_pattern_from_end_with_drop(a, false, true)); - run_test(|a| subslice_pattern_from_end_with_drop(a, false, false)); - run_test(|a| slice_pattern_reassign(a)); - run_test(|a| subslice_pattern_reassign(a)); - - run_test(|a| index_field_mixed_ends(a)); - run_test(|a| subslice_mixed_min_lengths(a, 0)); - run_test(|a| subslice_mixed_min_lengths(a, 1)); - run_test(|a| subslice_mixed_min_lengths(a, 2)); - run_test(|a| subslice_mixed_min_lengths(a, 3)); - run_test(|a| subslice_mixed_min_lengths(a, 4)); - run_test(|a| subslice_mixed_min_lengths(a, 5)); - run_test(|a| subslice_mixed_min_lengths(a, 6)); - run_test(|a| subslice_mixed_min_lengths(a, 7)); - - run_test(|a| move_ref_pattern(a)); - - run_test(|a| { + run_test!(|a| dynamic_init(a, false)); + run_test!(|a| dynamic_init(a, true)); + run_test!(|a| dynamic_drop(a, false)); + run_test!(|a| dynamic_drop(a, true)); + + run_test!(|a| assignment2(a, false, false)); + run_test!(|a| assignment2(a, false, true)); + run_test!(|a| assignment2(a, true, false)); + run_test!(|a| assignment2(a, true, true)); + + run_test!(|a| assignment1(a, false)); + run_test!(|a| assignment1(a, true)); + + run_test!(|a| array_simple(a)); + run_test!(|a| vec_simple(a)); + run_test!(|a| vec_unreachable(a)); + + run_test!(|a| struct_dynamic_drop(a, false, false, false)); + run_test!(|a| struct_dynamic_drop(a, false, false, true)); + run_test!(|a| struct_dynamic_drop(a, false, true, false)); + run_test!(|a| struct_dynamic_drop(a, false, true, true)); + run_test!(|a| struct_dynamic_drop(a, true, false, false)); + run_test!(|a| struct_dynamic_drop(a, true, false, true)); + run_test!(|a| struct_dynamic_drop(a, true, true, false)); + run_test!(|a| struct_dynamic_drop(a, true, true, true)); + + run_test!(|a| field_assignment(a, false)); + run_test!(|a| field_assignment(a, true)); + + run_test!(|a| generator(a, 0)); + run_test!(|a| generator(a, 1)); + run_test!(|a| generator(a, 2)); + run_test!(|a| generator(a, 3)); + + run_test!(|a| mixed_drop_and_nondrop(a)); + + run_test!(|a| slice_pattern_first(a)); + run_test!(|a| slice_pattern_middle(a)); + run_test!(|a| slice_pattern_two(a)); + run_test!(|a| slice_pattern_last(a)); + run_test!(|a| slice_pattern_one_of(a, 0)); + run_test!(|a| slice_pattern_one_of(a, 1)); + run_test!(|a| slice_pattern_one_of(a, 2)); + run_test!(|a| slice_pattern_one_of(a, 3)); + + run_test!(|a| subslice_pattern_from_end(a, true)); + run_test!(|a| subslice_pattern_from_end(a, false)); + run_test!(|a| subslice_pattern_from_end_with_drop(a, true, true)); + run_test!(|a| subslice_pattern_from_end_with_drop(a, true, false)); + run_test!(|a| subslice_pattern_from_end_with_drop(a, false, true)); + run_test!(|a| subslice_pattern_from_end_with_drop(a, false, false)); + run_test!(|a| slice_pattern_reassign(a)); + run_test!(|a| subslice_pattern_reassign(a)); + + run_test!(|a| index_field_mixed_ends(a)); + run_test!(|a| subslice_mixed_min_lengths(a, 0)); + run_test!(|a| subslice_mixed_min_lengths(a, 1)); + run_test!(|a| subslice_mixed_min_lengths(a, 2)); + run_test!(|a| subslice_mixed_min_lengths(a, 3)); + run_test!(|a| subslice_mixed_min_lengths(a, 4)); + run_test!(|a| subslice_mixed_min_lengths(a, 5)); + run_test!(|a| subslice_mixed_min_lengths(a, 6)); + run_test!(|a| subslice_mixed_min_lengths(a, 7)); + + run_test!(|a| move_ref_pattern(a)); + + run_test!(|a| { panic_after_return(a); }); - run_test(|a| { + run_test!(|a| { panic_after_return_expr(a); }); - run_test(|a| panic_after_init(a)); - run_test(|a| panic_after_init_temp(a)); - run_test(|a| panic_after_init_by_loop(a)); - - run_test(|a| bindings_after_at_dynamic_init_move(a, true)); - run_test(|a| bindings_after_at_dynamic_init_move(a, false)); - run_test(|a| bindings_after_at_dynamic_init_ref(a, true)); - run_test(|a| bindings_after_at_dynamic_init_ref(a, false)); - run_test(|a| bindings_after_at_dynamic_drop_move(a, true)); - run_test(|a| bindings_after_at_dynamic_drop_move(a, false)); - run_test(|a| bindings_after_at_dynamic_drop_ref(a, true)); - run_test(|a| bindings_after_at_dynamic_drop_ref(a, false)); - - run_test_nopanic(|a| union1(a)); + run_test!(|a| panic_after_init(a)); + run_test!(|a| panic_after_init_temp(a)); + run_test!(|a| panic_after_init_by_loop(a)); + run_test!(|a| panic_after_init_by_match(a, false)); + run_test!(|a| panic_after_init_by_match(a, true)); + run_test!(|a| panic_after_init_by_match_with_guard(a, false)); + run_test!(|a| panic_after_init_by_match_with_guard(a, true)); + run_test!(|a| panic_after_init_by_match_with_bindings_and_guard(a, false)); + run_test!(|a| panic_after_init_by_match_with_bindings_and_guard(a, true)); + run_test!(|a| panic_after_init_by_match_with_ref_bindings_and_guard(a, false)); + run_test!(|a| panic_after_init_by_match_with_ref_bindings_and_guard(a, true)); + run_test!(|a| panic_after_init_by_break_if(a, false)); + run_test!(|a| panic_after_init_by_break_if(a, true)); + + run_test!(|a| bindings_after_at_dynamic_init_move(a, true)); + run_test!(|a| bindings_after_at_dynamic_init_move(a, false)); + run_test!(|a| bindings_after_at_dynamic_init_ref(a, true)); + run_test!(|a| bindings_after_at_dynamic_init_ref(a, false)); + run_test!(|a| bindings_after_at_dynamic_drop_move(a, true)); + run_test!(|a| bindings_after_at_dynamic_drop_move(a, false)); + run_test!(|a| bindings_after_at_dynamic_drop_ref(a, true)); + run_test!(|a| bindings_after_at_dynamic_drop_ref(a, false)); + + run_test_nopanic(|a| union1(a), "|a| union1(a)"); } diff --git a/src/test/ui/error-codes/E0453.rs b/src/test/ui/error-codes/E0453.rs index 69155b0688bc0..6fa8dd9717fe6 100644 --- a/src/test/ui/error-codes/E0453.rs +++ b/src/test/ui/error-codes/E0453.rs @@ -1,8 +1,8 @@ #![forbid(non_snake_case)] #[allow(non_snake_case)] -//~^ ERROR allow(non_snake_case) overruled by outer forbid(non_snake_case) -//~| ERROR allow(non_snake_case) overruled by outer forbid(non_snake_case) -//~| ERROR allow(non_snake_case) overruled by outer forbid(non_snake_case) +//~^ ERROR allow(non_snake_case) incompatible +//~| ERROR allow(non_snake_case) incompatible +//~| ERROR allow(non_snake_case) incompatible fn main() { } diff --git a/src/test/ui/error-codes/E0453.stderr b/src/test/ui/error-codes/E0453.stderr index 138e8483461c9..21c43cc052e54 100644 --- a/src/test/ui/error-codes/E0453.stderr +++ b/src/test/ui/error-codes/E0453.stderr @@ -1,4 +1,4 @@ -error[E0453]: allow(non_snake_case) overruled by outer forbid(non_snake_case) +error[E0453]: allow(non_snake_case) incompatible with previous forbid --> $DIR/E0453.rs:3:9 | LL | #![forbid(non_snake_case)] @@ -7,7 +7,7 @@ LL | LL | #[allow(non_snake_case)] | ^^^^^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(non_snake_case) overruled by outer forbid(non_snake_case) +error[E0453]: allow(non_snake_case) incompatible with previous forbid --> $DIR/E0453.rs:3:9 | LL | #![forbid(non_snake_case)] @@ -16,7 +16,7 @@ LL | LL | #[allow(non_snake_case)] | ^^^^^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(non_snake_case) overruled by outer forbid(non_snake_case) +error[E0453]: allow(non_snake_case) incompatible with previous forbid --> $DIR/E0453.rs:3:9 | LL | #![forbid(non_snake_case)] diff --git a/src/test/ui/error-codes/E0496.stderr b/src/test/ui/error-codes/E0496.stderr index b0294eef04ef7..80ca2b1fbdb5d 100644 --- a/src/test/ui/error-codes/E0496.stderr +++ b/src/test/ui/error-codes/E0496.stderr @@ -4,7 +4,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop LL | impl<'a> Foo<'a> { | -- first declared here LL | fn f<'a>(x: &'a i32) { - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope error: aborting due to previous error diff --git a/src/test/ui/error-codes/e0119/conflict-with-std.stderr b/src/test/ui/error-codes/e0119/conflict-with-std.stderr index 9dc1a509cd09f..68551f4377591 100644 --- a/src/test/ui/error-codes/e0119/conflict-with-std.stderr +++ b/src/test/ui/error-codes/e0119/conflict-with-std.stderr @@ -6,7 +6,7 @@ LL | impl AsRef for Box { | = note: conflicting implementation in crate `alloc`: - impl AsRef for Box - where A: AllocRef, T: ?Sized; + where A: Allocator, T: ?Sized; error[E0119]: conflicting implementations of trait `std::convert::From` for type `S`: --> $DIR/conflict-with-std.rs:12:1 diff --git a/src/test/ui/expr/if/ifmt-bad-arg.rs b/src/test/ui/fmt/ifmt-bad-arg.rs similarity index 100% rename from src/test/ui/expr/if/ifmt-bad-arg.rs rename to src/test/ui/fmt/ifmt-bad-arg.rs diff --git a/src/test/ui/expr/if/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr similarity index 100% rename from src/test/ui/expr/if/ifmt-bad-arg.stderr rename to src/test/ui/fmt/ifmt-bad-arg.stderr diff --git a/src/test/ui/expr/if/ifmt-bad-format-args.rs b/src/test/ui/fmt/ifmt-bad-format-args.rs similarity index 100% rename from src/test/ui/expr/if/ifmt-bad-format-args.rs rename to src/test/ui/fmt/ifmt-bad-format-args.rs diff --git a/src/test/ui/expr/if/ifmt-bad-format-args.stderr b/src/test/ui/fmt/ifmt-bad-format-args.stderr similarity index 100% rename from src/test/ui/expr/if/ifmt-bad-format-args.stderr rename to src/test/ui/fmt/ifmt-bad-format-args.stderr diff --git a/src/test/ui/expr/if/ifmt-unimpl.rs b/src/test/ui/fmt/ifmt-unimpl.rs similarity index 100% rename from src/test/ui/expr/if/ifmt-unimpl.rs rename to src/test/ui/fmt/ifmt-unimpl.rs diff --git a/src/test/ui/expr/if/ifmt-unimpl.stderr b/src/test/ui/fmt/ifmt-unimpl.stderr similarity index 100% rename from src/test/ui/expr/if/ifmt-unimpl.stderr rename to src/test/ui/fmt/ifmt-unimpl.stderr diff --git a/src/test/ui/expr/if/ifmt-unknown-trait.rs b/src/test/ui/fmt/ifmt-unknown-trait.rs similarity index 100% rename from src/test/ui/expr/if/ifmt-unknown-trait.rs rename to src/test/ui/fmt/ifmt-unknown-trait.rs diff --git a/src/test/ui/expr/if/ifmt-unknown-trait.stderr b/src/test/ui/fmt/ifmt-unknown-trait.stderr similarity index 100% rename from src/test/ui/expr/if/ifmt-unknown-trait.stderr rename to src/test/ui/fmt/ifmt-unknown-trait.stderr diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr index d51c29080a0c9..95cebbb868115 100644 --- a/src/test/ui/generic-associated-types/shadowing.stderr +++ b/src/test/ui/generic-associated-types/shadowing.stderr @@ -20,7 +20,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop LL | trait Shadow<'a> { | -- first declared here LL | type Bar<'a>; - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope --> $DIR/shadowing.rs:14:14 @@ -28,7 +28,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop LL | impl<'a> NoShadow<'a> for &'a u32 { | -- first declared here LL | type Bar<'a> = i32; - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope error: aborting due to 4 previous errors diff --git a/src/test/ui/hygiene/hygienic-labels-in-let.stderr b/src/test/ui/hygiene/hygienic-labels-in-let.stderr index 3ff45a8a566bb..9e7811b807210 100644 --- a/src/test/ui/hygiene/hygienic-labels-in-let.stderr +++ b/src/test/ui/hygiene/hygienic-labels-in-let.stderr @@ -2,7 +2,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:16:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -19,7 +19,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:64:9 @@ -28,13 +28,13 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:16:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -51,7 +51,7 @@ LL | 'x: loop { $e } | ^^ | | | first declared here - | lifetime 'x already in scope + | label `'x` already in scope ... LL | loop_x!(break 'x); | ------------------ in this macro invocation @@ -62,7 +62,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:16:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -79,7 +79,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:76:9 @@ -88,7 +88,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:76:9 @@ -97,7 +97,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:76:9 @@ -106,13 +106,13 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:27:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -129,7 +129,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | while_true!(break 'x); | ---------------------- in this macro invocation @@ -140,7 +140,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:27:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -157,7 +157,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | while_true!(break 'x); | ---------------------- in this macro invocation @@ -168,7 +168,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:27:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -185,7 +185,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -194,7 +194,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -203,7 +203,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -212,7 +212,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -221,7 +221,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -230,13 +230,13 @@ LL | 'x: while 1 + 1 == 2 { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:39:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -253,7 +253,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -264,7 +264,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:39:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -281,7 +281,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -292,7 +292,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:39:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -309,7 +309,7 @@ LL | 'x: while 1 + 1 == 2 { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -320,7 +320,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:39:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here diff --git a/src/test/ui/hygiene/hygienic-labels.stderr b/src/test/ui/hygiene/hygienic-labels.stderr index 25098c25c82e3..275478d292d95 100644 --- a/src/test/ui/hygiene/hygienic-labels.stderr +++ b/src/test/ui/hygiene/hygienic-labels.stderr @@ -2,7 +2,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:13:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -19,7 +19,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: loop { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:54:5 @@ -28,13 +28,13 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: loop { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:13:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -51,7 +51,7 @@ LL | 'x: loop { $e } | ^^ | | | first declared here - | lifetime 'x already in scope + | label `'x` already in scope ... LL | loop_x!(break 'x); | ------------------ in this macro invocation @@ -62,7 +62,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:13:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -79,7 +79,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: while 1 + 1 == 2 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:63:5 @@ -88,7 +88,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:63:5 @@ -97,7 +97,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: while 1 + 1 == 2 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:63:5 @@ -106,13 +106,13 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:38:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -129,7 +129,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | while_x!(break 'x); | ------------------- in this macro invocation @@ -140,7 +140,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:38:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -157,7 +157,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | while_x!(break 'x); | ------------------- in this macro invocation @@ -168,7 +168,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:38:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: while 1 + 1 == 2 { | -- first declared here @@ -185,7 +185,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -194,7 +194,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -203,7 +203,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -212,7 +212,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -221,7 +221,7 @@ LL | 'x: while 1 + 1 == 2 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -230,13 +230,13 @@ LL | 'x: while 1 + 1 == 2 { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -253,7 +253,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -264,7 +264,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -281,7 +281,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -292,7 +292,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: while 1 + 1 == 2 { | -- first declared here @@ -306,7 +306,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: while 1 + 1 == 2 { $e } | -- first declared here @@ -320,7 +320,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here diff --git a/src/test/ui/in-band-lifetimes/shadow.stderr b/src/test/ui/in-band-lifetimes/shadow.stderr index a0a15d3aa8886..c7a6f3ac3ad14 100644 --- a/src/test/ui/in-band-lifetimes/shadow.stderr +++ b/src/test/ui/in-band-lifetimes/shadow.stderr @@ -4,7 +4,7 @@ error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scop LL | impl Foo<&'s u8> { | -- first declared here LL | fn bar<'s>(&self, x: &'s u8) {} - | ^^ lifetime 's already in scope + | ^^ lifetime `'s` already in scope error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scope --> $DIR/shadow.rs:8:19 @@ -13,7 +13,7 @@ LL | impl Foo<&'s u8> { | -- first declared here LL | fn bar<'s>(&self, x: &'s u8) {} LL | fn baz(x: for<'s> fn(&'s u32)) {} - | ^^ lifetime 's already in scope + | ^^ lifetime `'s` already in scope error: aborting due to 2 previous errors diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.rs b/src/test/ui/infinite/infinite-recursion-const-fn.rs index 34580407926f1..4209153116d94 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite/infinite-recursion-const-fn.rs @@ -1,8 +1,7 @@ //https://github.com/rust-lang/rust/issues/31364 const fn a() -> usize { - //~^ ERROR cycle detected when const-evaluating + checking `a` [E0391] - b() + b() //~ ERROR evaluation of constant value failed [E0080] } const fn b() -> usize { a() diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.stderr b/src/test/ui/infinite/infinite-recursion-const-fn.stderr index 7ccc7cc987f4e..620c9e110ff68 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite/infinite-recursion-const-fn.stderr @@ -1,21 +1,145 @@ -error[E0391]: cycle detected when const-evaluating + checking `a` - --> $DIR/infinite-recursion-const-fn.rs:3:1 - | -LL | const fn a() -> usize { - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `b`... - --> $DIR/infinite-recursion-const-fn.rs:7:1 - | -LL | const fn b() -> usize { - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating + checking `a`, completing the cycle -note: cycle used when const-evaluating + checking `ARR::{constant#0}` - --> $DIR/infinite-recursion-const-fn.rs:10:18 +error[E0080]: evaluation of constant value failed + --> $DIR/infinite-recursion-const-fn.rs:4:5 | +LL | b() + | ^^^ + | | + | reached the configured maximum number of stack frames + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 +... +LL | a() + | --- + | | + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 +LL | } LL | const ARR: [i32; a()] = [5; 6]; - | ^^^ + | --- inside `ARR::{constant#0}` at $DIR/infinite-recursion-const-fn.rs:9:18 error: aborting due to previous error -For more information about this error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/infinite/infinite-struct.rs b/src/test/ui/infinite/infinite-struct.rs new file mode 100644 index 0000000000000..70a203ea6e814 --- /dev/null +++ b/src/test/ui/infinite/infinite-struct.rs @@ -0,0 +1,10 @@ +struct Take(Take); +//~^ ERROR has infinite size +//~| ERROR cycle detected + +// check that we don't hang trying to find the tail of a recursive struct (#79437) +fn foo() -> Take { + Take(loop {}) +} + +fn main() {} diff --git a/src/test/ui/infinite/infinite-struct.stderr b/src/test/ui/infinite/infinite-struct.stderr new file mode 100644 index 0000000000000..d180670e38fda --- /dev/null +++ b/src/test/ui/infinite/infinite-struct.stderr @@ -0,0 +1,27 @@ +error[E0072]: recursive type `Take` has infinite size + --> $DIR/infinite-struct.rs:1:1 + | +LL | struct Take(Take); + | ^^^^^^^^^^^^----^^ + | | | + | | recursive without indirection + | recursive type has infinite size + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Take` representable + | +LL | struct Take(Box); + | ^^^^ ^ + +error[E0391]: cycle detected when computing drop-check constraints for `Take` + --> $DIR/infinite-struct.rs:1:1 + | +LL | struct Take(Take); + | ^^^^^^^^^^^^^^^^^^ + | + = note: ...which again requires computing drop-check constraints for `Take`, completing the cycle + = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: Take } }` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0072, E0391. +For more information about an error, try `rustc --explain E0072`. diff --git a/src/test/ui/issues/issue-12511.stderr b/src/test/ui/issues/issue-12511.stderr index 5f2b98c5237db..37e38ff60ae4b 100644 --- a/src/test/ui/issues/issue-12511.stderr +++ b/src/test/ui/issues/issue-12511.stderr @@ -1,25 +1,15 @@ -error[E0391]: cycle detected when computing the super predicates of `T1` - --> $DIR/issue-12511.rs:1:1 - | -LL | trait T1 : T2 { - | ^^^^^^^^^^^^^ - | -note: ...which requires computing the super traits of `T1`... +error[E0391]: cycle detected when computing the supertraits of `T1` --> $DIR/issue-12511.rs:1:12 | LL | trait T1 : T2 { | ^^ -note: ...which requires computing the super predicates of `T2`... - --> $DIR/issue-12511.rs:5:1 | -LL | trait T2 : T1 { - | ^^^^^^^^^^^^^ -note: ...which requires computing the super traits of `T2`... +note: ...which requires computing the supertraits of `T2`... --> $DIR/issue-12511.rs:5:12 | LL | trait T2 : T1 { | ^^ - = note: ...which again requires computing the super predicates of `T1`, completing the cycle + = note: ...which again requires computing the supertraits of `T1`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-12511.rs:1:1 | diff --git a/src/test/ui/issues/issue-20433.stderr b/src/test/ui/issues/issue-20433.stderr index d40946ae03f50..3f7226c79bf2a 100644 --- a/src/test/ui/issues/issue-20433.stderr +++ b/src/test/ui/issues/issue-20433.stderr @@ -6,7 +6,7 @@ LL | fn iceman(c: Vec<[i32]>) {} | ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | -LL | pub struct Vec { +LL | pub struct Vec { | - required by this bound in `Vec` | = help: the trait `Sized` is not implemented for `[i32]` diff --git a/src/test/ui/issues/issue-20772.stderr b/src/test/ui/issues/issue-20772.stderr index 4aecc7eab4628..d64636310a368 100644 --- a/src/test/ui/issues/issue-20772.stderr +++ b/src/test/ui/issues/issue-20772.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing the super traits of `T` with associated type name `Item` +error[E0391]: cycle detected when computing the supertraits of `T` --> $DIR/issue-20772.rs:1:1 | LL | / trait T : Iterator @@ -6,8 +6,8 @@ LL | | LL | | {} | |__^ | - = note: ...which again requires computing the super traits of `T` with associated type name `Item`, completing the cycle -note: cycle used when computing the super traits of `T` + = note: ...which again requires computing the supertraits of `T`, completing the cycle +note: cycle used when collecting item types in top-level module --> $DIR/issue-20772.rs:1:1 | LL | / trait T : Iterator diff --git a/src/test/ui/issues/issue-20825.stderr b/src/test/ui/issues/issue-20825.stderr index ccbe06d9c0d56..5f9709d1c649b 100644 --- a/src/test/ui/issues/issue-20825.stderr +++ b/src/test/ui/issues/issue-20825.stderr @@ -1,11 +1,11 @@ -error[E0391]: cycle detected when computing the super traits of `Processor` with associated type name `Input` +error[E0391]: cycle detected when computing the supertraits of `Processor` --> $DIR/issue-20825.rs:5:1 | LL | pub trait Processor: Subscriber { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing the super traits of `Processor` with associated type name `Input`, completing the cycle -note: cycle used when computing the super traits of `Processor` + = note: ...which again requires computing the supertraits of `Processor`, completing the cycle +note: cycle used when collecting item types in top-level module --> $DIR/issue-20825.rs:5:1 | LL | pub trait Processor: Subscriber { diff --git a/src/test/ui/issues/issue-22673.rs b/src/test/ui/issues/issue-22673.rs index 4b9b4d6b23da4..ba8057b684de8 100644 --- a/src/test/ui/issues/issue-22673.rs +++ b/src/test/ui/issues/issue-22673.rs @@ -1,6 +1,5 @@ -// check-pass - -trait Expr: PartialEq { +trait Expr : PartialEq { + //~^ ERROR: cycle detected type Item; } diff --git a/src/test/ui/issues/issue-22673.stderr b/src/test/ui/issues/issue-22673.stderr new file mode 100644 index 0000000000000..9e7e4b218b1c6 --- /dev/null +++ b/src/test/ui/issues/issue-22673.stderr @@ -0,0 +1,16 @@ +error[E0391]: cycle detected when computing the supertraits of `Expr` + --> $DIR/issue-22673.rs:1:1 + | +LL | trait Expr : PartialEq { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ...which again requires computing the supertraits of `Expr`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/issue-22673.rs:1:1 + | +LL | trait Expr : PartialEq { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/issues/issue-41974.stderr b/src/test/ui/issues/issue-41974.stderr index cc4b3707dd663..cde285f73d6b8 100644 --- a/src/test/ui/issues/issue-41974.stderr +++ b/src/test/ui/issues/issue-41974.stderr @@ -6,7 +6,7 @@ LL | impl Drop for T where T: A { | = note: conflicting implementation in crate `alloc`: - impl Drop for Box - where A: AllocRef, T: ?Sized; + where A: Allocator, T: ?Sized; = note: downstream crates may implement trait `A` for type `std::boxed::Box<_, _>` error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions diff --git a/src/test/ui/lint/forbid-error-capped.rs b/src/test/ui/lint/forbid-error-capped.rs new file mode 100644 index 0000000000000..b56471a756d1e --- /dev/null +++ b/src/test/ui/lint/forbid-error-capped.rs @@ -0,0 +1,15 @@ +// check-pass +// compile-args: --cap-lints=warn -Fwarnings + +// This checks that the forbid attribute checking is ignored when the forbidden +// lint is capped. + +#![forbid(warnings)] +#![allow(unused)] + +#[allow(unused)] +mod bar { + fn bar() {} +} + +fn main() {} diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs index 8e25227b59e63..f725304cf29d4 100644 --- a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs +++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs @@ -17,11 +17,11 @@ fn forbid_first(num: i32) -> i32 { #![forbid(unused)] #![deny(unused)] - //~^ ERROR: deny(unused) incompatible with previous forbid in same scope [E0453] + //~^ ERROR: deny(unused) incompatible with previous forbid #![warn(unused)] - //~^ ERROR: warn(unused) incompatible with previous forbid in same scope [E0453] + //~^ ERROR: warn(unused) incompatible with previous forbid #![allow(unused)] - //~^ ERROR: allow(unused) incompatible with previous forbid in same scope [E0453] + //~^ ERROR: allow(unused) incompatible with previous forbid num * num } diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr index 3951c511bf432..9f107411c102a 100644 --- a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr +++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr @@ -1,28 +1,28 @@ -error[E0453]: deny(unused) incompatible with previous forbid in same scope +error[E0453]: deny(unused) incompatible with previous forbid --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:19:13 | LL | #![forbid(unused)] | ------ `forbid` level set here LL | #![deny(unused)] - | ^^^^^^ + | ^^^^^^ overruled by previous forbid -error[E0453]: warn(unused) incompatible with previous forbid in same scope +error[E0453]: warn(unused) incompatible with previous forbid --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:21:13 | LL | #![forbid(unused)] | ------ `forbid` level set here ... LL | #![warn(unused)] - | ^^^^^^ + | ^^^^^^ overruled by previous forbid -error[E0453]: allow(unused) incompatible with previous forbid in same scope +error[E0453]: allow(unused) incompatible with previous forbid --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:23:14 | LL | #![forbid(unused)] | ------ `forbid` level set here ... LL | #![allow(unused)] - | ^^^^^^ + | ^^^^^^ overruled by previous forbid error: aborting due to 3 previous errors diff --git a/src/test/ui/lint/lint-forbid-attr.rs b/src/test/ui/lint/lint-forbid-attr.rs index 13b28e8830b62..13ebb6dccd822 100644 --- a/src/test/ui/lint/lint-forbid-attr.rs +++ b/src/test/ui/lint/lint-forbid-attr.rs @@ -1,8 +1,8 @@ #![forbid(deprecated)] #[allow(deprecated)] -//~^ ERROR allow(deprecated) overruled by outer forbid(deprecated) -//~| ERROR allow(deprecated) overruled by outer forbid(deprecated) -//~| ERROR allow(deprecated) overruled by outer forbid(deprecated) +//~^ ERROR allow(deprecated) incompatible +//~| ERROR allow(deprecated) incompatible +//~| ERROR allow(deprecated) incompatible fn main() { } diff --git a/src/test/ui/lint/lint-forbid-attr.stderr b/src/test/ui/lint/lint-forbid-attr.stderr index bf138c317e93d..cb0b25d11153e 100644 --- a/src/test/ui/lint/lint-forbid-attr.stderr +++ b/src/test/ui/lint/lint-forbid-attr.stderr @@ -1,4 +1,4 @@ -error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) +error[E0453]: allow(deprecated) incompatible with previous forbid --> $DIR/lint-forbid-attr.rs:3:9 | LL | #![forbid(deprecated)] @@ -7,7 +7,7 @@ LL | LL | #[allow(deprecated)] | ^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) +error[E0453]: allow(deprecated) incompatible with previous forbid --> $DIR/lint-forbid-attr.rs:3:9 | LL | #![forbid(deprecated)] @@ -16,7 +16,7 @@ LL | LL | #[allow(deprecated)] | ^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) +error[E0453]: allow(deprecated) incompatible with previous forbid --> $DIR/lint-forbid-attr.rs:3:9 | LL | #![forbid(deprecated)] diff --git a/src/test/ui/lint/lint-forbid-cmdline.rs b/src/test/ui/lint/lint-forbid-cmdline.rs index 821470c86860a..38bb8d29d3f63 100644 --- a/src/test/ui/lint/lint-forbid-cmdline.rs +++ b/src/test/ui/lint/lint-forbid-cmdline.rs @@ -1,7 +1,7 @@ // compile-flags: -F deprecated -#[allow(deprecated)] //~ ERROR allow(deprecated) overruled by outer forbid(deprecated) - //~| ERROR allow(deprecated) overruled by outer forbid(deprecated) - //~| ERROR allow(deprecated) overruled by outer forbid(deprecated) +#[allow(deprecated)] //~ ERROR allow(deprecated) incompatible + //~| ERROR allow(deprecated) incompatible + //~| ERROR allow(deprecated) incompatible fn main() { } diff --git a/src/test/ui/lint/lint-forbid-cmdline.stderr b/src/test/ui/lint/lint-forbid-cmdline.stderr index 89a4445d80068..5b1b015c4ddb9 100644 --- a/src/test/ui/lint/lint-forbid-cmdline.stderr +++ b/src/test/ui/lint/lint-forbid-cmdline.stderr @@ -1,4 +1,4 @@ -error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) +error[E0453]: allow(deprecated) incompatible with previous forbid --> $DIR/lint-forbid-cmdline.rs:3:9 | LL | #[allow(deprecated)] @@ -6,7 +6,7 @@ LL | #[allow(deprecated)] | = note: `forbid` lint level was set on command line -error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) +error[E0453]: allow(deprecated) incompatible with previous forbid --> $DIR/lint-forbid-cmdline.rs:3:9 | LL | #[allow(deprecated)] @@ -14,7 +14,7 @@ LL | #[allow(deprecated)] | = note: `forbid` lint level was set on command line -error[E0453]: allow(deprecated) overruled by outer forbid(deprecated) +error[E0453]: allow(deprecated) incompatible with previous forbid --> $DIR/lint-forbid-cmdline.rs:3:9 | LL | #[allow(deprecated)] diff --git a/src/test/ui/lint/outer-forbid.rs b/src/test/ui/lint/outer-forbid.rs index 2a38565f60364..d45848bf706f3 100644 --- a/src/test/ui/lint/outer-forbid.rs +++ b/src/test/ui/lint/outer-forbid.rs @@ -4,21 +4,25 @@ // subsequent allowance of a lint group containing it (here, `nonstandard_style`). See // Issue #42873. +// If you turn off deduplicate diagnostics (which rustc turns on by default but +// compiletest turns off when it runs ui tests), then the errors are +// (unfortunately) repeated here because the checking is done as we read in the +// errors, and currently that happens two or three different times, depending on +// compiler flags. +// +// The test is much cleaner if we deduplicate, though. + +// compile-flags: -Z deduplicate-diagnostics=yes + #![forbid(unused, non_snake_case)] -#[allow(unused_variables)] //~ ERROR overruled - //~| ERROR overruled - //~| ERROR overruled +#[allow(unused_variables)] //~ ERROR incompatible with previous fn foo() {} -#[allow(unused)] //~ ERROR overruled - //~| ERROR overruled - //~| ERROR overruled +#[allow(unused)] //~ ERROR incompatible with previous fn bar() {} -#[allow(nonstandard_style)] //~ ERROR overruled - //~| ERROR overruled - //~| ERROR overruled +#[allow(nonstandard_style)] //~ ERROR incompatible with previous fn main() { println!("hello forbidden world") } diff --git a/src/test/ui/lint/outer-forbid.stderr b/src/test/ui/lint/outer-forbid.stderr index b2e638e7af978..c012c20697e16 100644 --- a/src/test/ui/lint/outer-forbid.stderr +++ b/src/test/ui/lint/outer-forbid.stderr @@ -1,68 +1,14 @@ -error[E0453]: allow(unused_variables) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:9:9 - | -LL | #![forbid(unused, non_snake_case)] - | ------ `forbid` level set here -LL | -LL | #[allow(unused_variables)] - | ^^^^^^^^^^^^^^^^ overruled by previous forbid - -error[E0453]: allow(unused) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:14:9 - | -LL | #![forbid(unused, non_snake_case)] - | ------ `forbid` level set here -... -LL | #[allow(unused)] - | ^^^^^^ overruled by previous forbid - -error[E0453]: allow(nonstandard_style) overruled by outer forbid(non_snake_case) - --> $DIR/outer-forbid.rs:19:9 - | -LL | #![forbid(unused, non_snake_case)] - | -------------- `forbid` level set here -... -LL | #[allow(nonstandard_style)] - | ^^^^^^^^^^^^^^^^^ overruled by previous forbid - -error[E0453]: allow(unused_variables) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:9:9 - | -LL | #![forbid(unused, non_snake_case)] - | ------ `forbid` level set here -LL | -LL | #[allow(unused_variables)] - | ^^^^^^^^^^^^^^^^ overruled by previous forbid - -error[E0453]: allow(unused) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:14:9 - | -LL | #![forbid(unused, non_snake_case)] - | ------ `forbid` level set here -... -LL | #[allow(unused)] - | ^^^^^^ overruled by previous forbid - -error[E0453]: allow(nonstandard_style) overruled by outer forbid(non_snake_case) +error[E0453]: allow(unused_variables) incompatible with previous forbid --> $DIR/outer-forbid.rs:19:9 | -LL | #![forbid(unused, non_snake_case)] - | -------------- `forbid` level set here -... -LL | #[allow(nonstandard_style)] - | ^^^^^^^^^^^^^^^^^ overruled by previous forbid - -error[E0453]: allow(unused_variables) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:9:9 - | LL | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here LL | LL | #[allow(unused_variables)] | ^^^^^^^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(unused) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:14:9 +error[E0453]: allow(unused) incompatible with previous forbid + --> $DIR/outer-forbid.rs:22:9 | LL | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here @@ -70,8 +16,8 @@ LL | #![forbid(unused, non_snake_case)] LL | #[allow(unused)] | ^^^^^^ overruled by previous forbid -error[E0453]: allow(nonstandard_style) overruled by outer forbid(non_snake_case) - --> $DIR/outer-forbid.rs:19:9 +error[E0453]: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/outer-forbid.rs:25:9 | LL | #![forbid(unused, non_snake_case)] | -------------- `forbid` level set here @@ -79,6 +25,6 @@ LL | #![forbid(unused, non_snake_case)] LL | #[allow(nonstandard_style)] | ^^^^^^^^^^^^^^^^^ overruled by previous forbid -error: aborting due to 9 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/reasons-forbidden.rs b/src/test/ui/lint/reasons-forbidden.rs index 5f6764c789d00..9c2edec4d5214 100644 --- a/src/test/ui/lint/reasons-forbidden.rs +++ b/src/test/ui/lint/reasons-forbidden.rs @@ -1,13 +1,19 @@ #![feature(lint_reasons)] +// If you turn off deduplicate diagnostics (which rustc turns on by default but +// compiletest turns off when it runs ui tests), then the errors are +// (unfortunately) repeated here because the checking is done as we read in the +// errors, and currently that happens two or three different times, depending on +// compiler flags. +// +// The test is much cleaner if we deduplicate, though. + +// compile-flags: -Z deduplicate-diagnostics=yes + #![forbid( unsafe_code, //~^ NOTE `forbid` level set here - //~| NOTE `forbid` level set here - //~| NOTE `forbid` level set here - //~| NOTE `forbid` level set here - //~| NOTE `forbid` level set here - //~| NOTE `forbid` level set here + //~| NOTE the lint level is defined here reason = "our errors & omissions insurance policy doesn't cover unsafe Rust" )] @@ -17,25 +23,12 @@ fn main() { let a_billion_dollar_mistake = ptr::null(); #[allow(unsafe_code)] - //~^ ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) - //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) - //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) - //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) - //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) - //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) - //~| NOTE overruled by previous forbid - //~| NOTE overruled by previous forbid - //~| NOTE overruled by previous forbid - //~| NOTE overruled by previous forbid - //~| NOTE overruled by previous forbid - //~| NOTE overruled by previous forbid - //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust - //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust - //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust - //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust - //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust + //~^ ERROR allow(unsafe_code) incompatible with previous forbid //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust + //~| NOTE overruled by previous forbid unsafe { + //~^ ERROR usage of an `unsafe` block + //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust *a_billion_dollar_mistake } } diff --git a/src/test/ui/lint/reasons-forbidden.stderr b/src/test/ui/lint/reasons-forbidden.stderr index eed9c8d566ecd..ab6f19a019d43 100644 --- a/src/test/ui/lint/reasons-forbidden.stderr +++ b/src/test/ui/lint/reasons-forbidden.stderr @@ -1,5 +1,5 @@ -error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:19:13 +error[E0453]: allow(unsafe_code) incompatible with previous forbid + --> $DIR/reasons-forbidden.rs:25:13 | LL | unsafe_code, | ----------- `forbid` level set here @@ -9,61 +9,23 @@ LL | #[allow(unsafe_code)] | = note: our errors & omissions insurance policy doesn't cover unsafe Rust -error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:19:13 +error: usage of an `unsafe` block + --> $DIR/reasons-forbidden.rs:29:5 | -LL | unsafe_code, - | ----------- `forbid` level set here -... -LL | #[allow(unsafe_code)] - | ^^^^^^^^^^^ overruled by previous forbid - | - = note: our errors & omissions insurance policy doesn't cover unsafe Rust - -error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:19:13 - | -LL | unsafe_code, - | ----------- `forbid` level set here -... -LL | #[allow(unsafe_code)] - | ^^^^^^^^^^^ overruled by previous forbid +LL | / unsafe { +LL | | +LL | | +LL | | *a_billion_dollar_mistake +LL | | } + | |_____^ | = note: our errors & omissions insurance policy doesn't cover unsafe Rust - -error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:19:13 +note: the lint level is defined here + --> $DIR/reasons-forbidden.rs:14:5 | LL | unsafe_code, - | ----------- `forbid` level set here -... -LL | #[allow(unsafe_code)] - | ^^^^^^^^^^^ overruled by previous forbid - | - = note: our errors & omissions insurance policy doesn't cover unsafe Rust - -error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:19:13 - | -LL | unsafe_code, - | ----------- `forbid` level set here -... -LL | #[allow(unsafe_code)] - | ^^^^^^^^^^^ overruled by previous forbid - | - = note: our errors & omissions insurance policy doesn't cover unsafe Rust - -error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:19:13 - | -LL | unsafe_code, - | ----------- `forbid` level set here -... -LL | #[allow(unsafe_code)] - | ^^^^^^^^^^^ overruled by previous forbid - | - = note: our errors & omissions insurance policy doesn't cover unsafe Rust + | ^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/unused_labels.stderr b/src/test/ui/lint/unused_labels.stderr index 443faebd0f802..4bb1a437d2409 100644 --- a/src/test/ui/lint/unused_labels.stderr +++ b/src/test/ui/lint/unused_labels.stderr @@ -59,7 +59,7 @@ LL | 'many_used_shadowed: for _ in 0..10 { | ------------------- first declared here LL | LL | 'many_used_shadowed: for _ in 0..10 { - | ^^^^^^^^^^^^^^^^^^^ lifetime 'many_used_shadowed already in scope + | ^^^^^^^^^^^^^^^^^^^ label `'many_used_shadowed` already in scope warning: 9 warnings emitted diff --git a/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr b/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr index 3c8e2938d4188..724c36e5203e6 100644 --- a/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr +++ b/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr @@ -4,7 +4,7 @@ warning: label name `'fl` shadows a label name that is already in scope LL | { 'fl: for _ in 0..10 { break; } } | --- first declared here LL | { 'fl: loop { break; } } - | ^^^ lifetime 'fl already in scope + | ^^^ label `'fl` already in scope warning: label name `'lf` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:16:7 @@ -12,7 +12,7 @@ warning: label name `'lf` shadows a label name that is already in scope LL | { 'lf: loop { break; } } | --- first declared here LL | { 'lf: for _ in 0..10 { break; } } - | ^^^ lifetime 'lf already in scope + | ^^^ label `'lf` already in scope warning: label name `'wl` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:18:7 @@ -20,7 +20,7 @@ warning: label name `'wl` shadows a label name that is already in scope LL | { 'wl: while 2 > 1 { break; } } | --- first declared here LL | { 'wl: loop { break; } } - | ^^^ lifetime 'wl already in scope + | ^^^ label `'wl` already in scope warning: label name `'lw` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:20:7 @@ -28,7 +28,7 @@ warning: label name `'lw` shadows a label name that is already in scope LL | { 'lw: loop { break; } } | --- first declared here LL | { 'lw: while 2 > 1 { break; } } - | ^^^ lifetime 'lw already in scope + | ^^^ label `'lw` already in scope warning: label name `'fw` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:22:7 @@ -36,7 +36,7 @@ warning: label name `'fw` shadows a label name that is already in scope LL | { 'fw: for _ in 0..10 { break; } } | --- first declared here LL | { 'fw: while 2 > 1 { break; } } - | ^^^ lifetime 'fw already in scope + | ^^^ label `'fw` already in scope warning: label name `'wf` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:24:7 @@ -44,7 +44,7 @@ warning: label name `'wf` shadows a label name that is already in scope LL | { 'wf: while 2 > 1 { break; } } | --- first declared here LL | { 'wf: for _ in 0..10 { break; } } - | ^^^ lifetime 'wf already in scope + | ^^^ label `'wf` already in scope warning: label name `'tl` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:26:7 @@ -52,7 +52,7 @@ warning: label name `'tl` shadows a label name that is already in scope LL | { 'tl: while let Some(_) = None:: { break; } } | --- first declared here LL | { 'tl: loop { break; } } - | ^^^ lifetime 'tl already in scope + | ^^^ label `'tl` already in scope warning: label name `'lt` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:28:7 @@ -60,7 +60,7 @@ warning: label name `'lt` shadows a label name that is already in scope LL | { 'lt: loop { break; } } | --- first declared here LL | { 'lt: while let Some(_) = None:: { break; } } - | ^^^ lifetime 'lt already in scope + | ^^^ label `'lt` already in scope warning: 8 warnings emitted diff --git a/src/test/ui/loops/loops-reject-duplicate-labels.stderr b/src/test/ui/loops/loops-reject-duplicate-labels.stderr index 5a3e5158fed8c..2d11281201797 100644 --- a/src/test/ui/loops/loops-reject-duplicate-labels.stderr +++ b/src/test/ui/loops/loops-reject-duplicate-labels.stderr @@ -4,7 +4,7 @@ warning: label name `'fl` shadows a label name that is already in scope LL | 'fl: for _ in 0..10 { break; } | --- first declared here LL | 'fl: loop { break; } - | ^^^ lifetime 'fl already in scope + | ^^^ label `'fl` already in scope warning: label name `'lf` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:14:5 @@ -12,7 +12,7 @@ warning: label name `'lf` shadows a label name that is already in scope LL | 'lf: loop { break; } | --- first declared here LL | 'lf: for _ in 0..10 { break; } - | ^^^ lifetime 'lf already in scope + | ^^^ label `'lf` already in scope warning: label name `'wl` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:16:5 @@ -20,7 +20,7 @@ warning: label name `'wl` shadows a label name that is already in scope LL | 'wl: while 2 > 1 { break; } | --- first declared here LL | 'wl: loop { break; } - | ^^^ lifetime 'wl already in scope + | ^^^ label `'wl` already in scope warning: label name `'lw` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:18:5 @@ -28,7 +28,7 @@ warning: label name `'lw` shadows a label name that is already in scope LL | 'lw: loop { break; } | --- first declared here LL | 'lw: while 2 > 1 { break; } - | ^^^ lifetime 'lw already in scope + | ^^^ label `'lw` already in scope warning: label name `'fw` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:20:5 @@ -36,7 +36,7 @@ warning: label name `'fw` shadows a label name that is already in scope LL | 'fw: for _ in 0..10 { break; } | --- first declared here LL | 'fw: while 2 > 1 { break; } - | ^^^ lifetime 'fw already in scope + | ^^^ label `'fw` already in scope warning: label name `'wf` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:22:5 @@ -44,7 +44,7 @@ warning: label name `'wf` shadows a label name that is already in scope LL | 'wf: while 2 > 1 { break; } | --- first declared here LL | 'wf: for _ in 0..10 { break; } - | ^^^ lifetime 'wf already in scope + | ^^^ label `'wf` already in scope warning: label name `'tl` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:24:5 @@ -52,7 +52,7 @@ warning: label name `'tl` shadows a label name that is already in scope LL | 'tl: while let Some(_) = None:: { break; } | --- first declared here LL | 'tl: loop { break; } - | ^^^ lifetime 'tl already in scope + | ^^^ label `'tl` already in scope warning: label name `'lt` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:26:5 @@ -60,7 +60,7 @@ warning: label name `'lt` shadows a label name that is already in scope LL | 'lt: loop { break; } | --- first declared here LL | 'lt: while let Some(_) = None:: { break; } - | ^^^ lifetime 'lt already in scope + | ^^^ label `'lt` already in scope warning: 8 warnings emitted diff --git a/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr b/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr index c27e61190bbec..0d96c0b3a35b6 100644 --- a/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr +++ b/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr @@ -4,7 +4,7 @@ warning: label name `'a` shadows a lifetime name that is already in scope LL | fn foo<'a>() { | -- first declared here LL | 'a: loop { break 'a; } - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:35:13 @@ -13,7 +13,7 @@ LL | impl<'bad, 'c> Struct<'bad, 'c> { | ---- first declared here LL | fn meth_bad(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:42:13 @@ -22,7 +22,7 @@ LL | impl<'b, 'bad> Struct<'b, 'bad> { | ---- first declared here LL | fn meth_bad2(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:49:13 @@ -30,7 +30,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad3<'bad>(x: &'bad i8) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:54:13 @@ -38,7 +38,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad4<'a,'bad>(x: &'a i8, y: &'bad i8) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:61:13 @@ -47,7 +47,7 @@ LL | impl <'bad, 'e> Enum<'bad, 'e> { | ---- first declared here LL | fn meth_bad(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:67:13 @@ -56,7 +56,7 @@ LL | impl <'d, 'bad> Enum<'d, 'bad> { | ---- first declared here LL | fn meth_bad2(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:73:13 @@ -64,7 +64,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad3<'bad>(x: &'bad i8) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:78:13 @@ -72,7 +72,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad4<'a,'bad>(x: &'bad i8) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:88:13 @@ -81,7 +81,7 @@ LL | trait HasDefaultMethod1<'bad> { | ---- first declared here ... LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:94:13 @@ -90,7 +90,7 @@ LL | trait HasDefaultMethod2<'a,'bad> { | ---- first declared here LL | fn meth_bad(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:100:13 @@ -98,7 +98,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad<'bad>(&self) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: 12 warnings emitted diff --git a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr index b31ef273fc625..dcee1a8009053 100644 --- a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr +++ b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr @@ -4,7 +4,7 @@ warning: lifetime name `'a` shadows a label name that is already in scope LL | 'a: loop { | -- first declared here LL | let b = Box::new(|x: &i8| *x) as Box Fn(&'a i8) -> i8>; - | ^^ lifetime 'a already in scope + | ^^ label `'a` already in scope warning: 1 warning emitted diff --git a/src/test/ui/macros/macro-lifetime-used-with-labels.stderr b/src/test/ui/macros/macro-lifetime-used-with-labels.stderr index 98ee85d908d4e..68f885e9e45c7 100644 --- a/src/test/ui/macros/macro-lifetime-used-with-labels.stderr +++ b/src/test/ui/macros/macro-lifetime-used-with-labels.stderr @@ -2,7 +2,7 @@ warning: label name `'b` shadows a label name that is already in scope --> $DIR/macro-lifetime-used-with-labels.rs:21:9 | LL | 'b: loop { - | ^^ lifetime 'b already in scope + | ^^ label `'b` already in scope ... LL | 'b: loop { | -- first declared here diff --git a/src/test/ui/realloc-16687.rs b/src/test/ui/realloc-16687.rs index 2e07fdcbe830c..92d98c16c60d8 100644 --- a/src/test/ui/realloc-16687.rs +++ b/src/test/ui/realloc-16687.rs @@ -7,7 +7,7 @@ #![feature(allocator_api)] #![feature(slice_ptr_get)] -use std::alloc::{handle_alloc_error, AllocRef, Global, Layout}; +use std::alloc::{handle_alloc_error, Allocator, Global, Layout}; use std::ptr::{self, NonNull}; fn main() { @@ -42,7 +42,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = Global.allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); if PRINT { println!("allocate({:?}) = {:?}", layout, ptr); @@ -56,7 +56,7 @@ unsafe fn test_triangle() -> bool { println!("deallocate({:?}, {:?}", ptr, layout); } - Global.dealloc(NonNull::new_unchecked(ptr), layout); + Global.deallocate(NonNull::new_unchecked(ptr), layout); } unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { diff --git a/src/test/ui/regions/regions-mock-codegen.rs b/src/test/ui/regions/regions-mock-codegen.rs index ad4b9c352aefd..9d0ca76e4095d 100644 --- a/src/test/ui/regions/regions-mock-codegen.rs +++ b/src/test/ui/regions/regions-mock-codegen.rs @@ -4,7 +4,7 @@ // pretty-expanded FIXME #23616 #![feature(allocator_api)] -use std::alloc::{handle_alloc_error, AllocRef, Global, Layout}; +use std::alloc::{handle_alloc_error, Allocator, Global, Layout}; use std::ptr::NonNull; struct arena(()); @@ -22,23 +22,23 @@ struct Ccx { x: isize, } -fn alloc(_bcx: &arena) -> &Bcx<'_> { +fn allocate(_bcx: &arena) -> &Bcx<'_> { unsafe { let layout = Layout::new::(); - let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = Global.allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); &*(ptr.as_ptr() as *const _) } } fn h<'a>(bcx: &'a Bcx<'a>) -> &'a Bcx<'a> { - return alloc(bcx.fcx.arena); + return allocate(bcx.fcx.arena); } fn g(fcx: &Fcx) { let bcx = Bcx { fcx }; let bcx2 = h(&bcx); unsafe { - Global.dealloc(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::()); + Global.deallocate(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::()); } } diff --git a/src/test/ui/shadowed/shadowed-lifetime.stderr b/src/test/ui/shadowed/shadowed-lifetime.stderr index 5ea3d926430f8..68cc505d36d26 100644 --- a/src/test/ui/shadowed/shadowed-lifetime.stderr +++ b/src/test/ui/shadowed/shadowed-lifetime.stderr @@ -4,7 +4,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop LL | impl<'a> Foo<'a> { | -- first declared here LL | fn shadow_in_method<'a>(&'a self) -> &'a isize { - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope error[E0496]: lifetime name `'b` shadows a lifetime name that is already in scope --> $DIR/shadowed-lifetime.rs:12:20 @@ -12,7 +12,7 @@ error[E0496]: lifetime name `'b` shadows a lifetime name that is already in scop LL | fn shadow_in_type<'b>(&'b self) -> &'b isize { | -- first declared here LL | let x: for<'b> fn(&'b isize) = panic!(); - | ^^ lifetime 'b already in scope + | ^^ lifetime `'b` already in scope error: aborting due to 2 previous errors diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr index bf2436a535fd4..97089f7df5263 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr @@ -110,5 +110,5 @@ LL | #[rustc_deprecated(since = "a", reason = "text")] error: aborting due to 18 previous errors -Some errors have detailed explanations: E0539, E0541, E0550. +Some errors have detailed explanations: E0539, E0541, E0546, E0550. For more information about an error, try `rustc --explain E0539`. diff --git a/src/test/ui/traits/issue-79458.rs b/src/test/ui/traits/issue-79458.rs new file mode 100644 index 0000000000000..a41add6a1ccea --- /dev/null +++ b/src/test/ui/traits/issue-79458.rs @@ -0,0 +1,10 @@ +// Negative implementations should not be shown in trait suggestions. +// This is a regression test of #79458. + +#[derive(Clone)] +struct Foo<'a, T> { + bar: &'a mut T + //~^ ERROR the trait bound `&mut T: Clone` is not satisfied +} + +fn main() {} diff --git a/src/test/ui/traits/issue-79458.stderr b/src/test/ui/traits/issue-79458.stderr new file mode 100644 index 0000000000000..54947b57c03b1 --- /dev/null +++ b/src/test/ui/traits/issue-79458.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&mut T: Clone` is not satisfied + --> $DIR/issue-79458.rs:6:5 + | +LL | bar: &'a mut T + | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `&mut T` + | + = help: the following implementations were found: + <&T as Clone> + = note: `Clone` is implemented for `&T`, but not for `&mut T` + = note: required by `clone` + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index 2e23ddd905361..09cbb8753387a 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -22,7 +22,7 @@ LL | fn clone(&self) -> Self; | LL | / pub struct Box< LL | | T: ?Sized, -LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, +LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, LL | | >(Unique, A); | |________________- doesn't satisfy `Box: Clone` | diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index d533724a009dc..bc081024182af 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -19,7 +19,7 @@ LL | fn clone(&self) -> Self; | LL | / pub struct Box< LL | | T: ?Sized, -LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, +LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, LL | | >(Unique, A); | |________________- doesn't satisfy `Box: Clone` | diff --git a/src/tools/cargo b/src/tools/cargo index bfca1cd22bf51..63d0fe43449ad 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit bfca1cd22bf514d5f2b6c1089b0ded0ba7dfaa6e +Subproject commit 63d0fe43449adcb316d34d98a982b597faca4178 diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 24ef98cd784d8..eba02333c8cb2 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -17,6 +17,7 @@ pub enum Mode { DebugInfo, Codegen, Rustdoc, + RustdocJson, CodegenUnits, Incremental, RunMake, @@ -48,6 +49,7 @@ impl FromStr for Mode { "debuginfo" => Ok(DebugInfo), "codegen" => Ok(Codegen), "rustdoc" => Ok(Rustdoc), + "rustdoc-json" => Ok(RustdocJson), "codegen-units" => Ok(CodegenUnits), "incremental" => Ok(Incremental), "run-make" => Ok(RunMake), @@ -70,6 +72,7 @@ impl fmt::Display for Mode { DebugInfo => "debuginfo", Codegen => "codegen", Rustdoc => "rustdoc", + RustdocJson => "rustdoc-json", CodegenUnits => "codegen-units", Incremental => "incremental", RunMake => "run-make", diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 32347db5dbb1c..5177dae8a6604 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -68,7 +68,7 @@ pub fn parse_config(args: Vec) -> Config { "mode", "which sort of compile tests to run", "compile-fail | run-fail | run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ - codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", + | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", ) .reqopt( "", @@ -508,8 +508,6 @@ fn common_inputs_stamp(config: &Config) -> Stamp { stamp.add_path(&rustdoc_path); stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py")); } - // FIXME(richkadel): Do I need to add an `if let Some(rust_demangler_path) contribution to the - // stamp here as well? // Compiletest itself. stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/")); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1b9f0089dced0..e9089b4b15baa 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2,7 +2,7 @@ use crate::common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT}; use crate::common::{output_base_dir, output_base_name, output_testname_unique}; -use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, Ui}; +use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Ui}; use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc}; use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{CompileFail, Pretty, RunFail, RunPassValgrind}; @@ -342,6 +342,7 @@ impl<'test> TestCx<'test> { DebugInfo => self.run_debuginfo_test(), Codegen => self.run_codegen_test(), Rustdoc => self.run_rustdoc_test(), + RustdocJson => self.run_rustdoc_json_test(), CodegenUnits => self.run_codegen_units_test(), Incremental => self.run_incremental_test(), RunMake => self.run_rmake_test(), @@ -1600,6 +1601,10 @@ impl<'test> TestCx<'test> { .arg(&self.testpaths.file) .args(&self.props.compile_flags); + if self.config.mode == RustdocJson { + rustdoc.arg("--output-format").arg("json"); + } + if let Some(ref linker) = self.config.linker { rustdoc.arg(format!("-Clinker={}", linker)); } @@ -1887,7 +1892,9 @@ impl<'test> TestCx<'test> { } fn is_rustdoc(&self) -> bool { - self.config.src_base.ends_with("rustdoc-ui") || self.config.src_base.ends_with("rustdoc-js") + self.config.src_base.ends_with("rustdoc-ui") + || self.config.src_base.ends_with("rustdoc-js") + || self.config.src_base.ends_with("rustdoc-json") } fn make_compile_args( @@ -1968,8 +1975,8 @@ impl<'test> TestCx<'test> { rustc.arg(dir_opt); } - RunFail | RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RunMake - | CodegenUnits | JsDocTest | Assembly => { + RunFail | RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson + | RunMake | CodegenUnits | JsDocTest | Assembly => { // do not use JSON output } } @@ -2466,6 +2473,48 @@ impl<'test> TestCx<'test> { eprintln!("{}", String::from_utf8_lossy(&output.stderr)); } + fn run_rustdoc_json_test(&self) { + //FIXME: Add bless option. + + assert!(self.revision.is_none(), "revisions not relevant here"); + + let out_dir = self.output_base_dir(); + let _ = fs::remove_dir_all(&out_dir); + create_dir_all(&out_dir).unwrap(); + + let proc_res = self.document(&out_dir); + if !proc_res.status.success() { + self.fatal_proc_rec("rustdoc failed!", &proc_res); + } + + let root = self.config.find_rust_src_root().unwrap(); + let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); + json_out.set_extension("json"); + let res = self.cmd2procres( + Command::new(&self.config.docck_python) + .arg(root.join("src/test/rustdoc-json/check_missing_items.py")) + .arg(&json_out), + ); + + if !res.status.success() { + self.fatal_proc_rec("check_missing_items failed!", &res); + } + + let mut expected = self.testpaths.file.clone(); + expected.set_extension("expected"); + let res = self.cmd2procres( + Command::new(&self.config.docck_python) + .arg(root.join("src/test/rustdoc-json/compare.py")) + .arg(&expected) + .arg(&json_out) + .arg(&expected.parent().unwrap()), + ); + + if !res.status.success() { + self.fatal_proc_rec("compare failed!", &res); + } + } + fn get_lines>( &self, path: &P, diff --git a/src/tools/miri b/src/tools/miri index 47acece7aa25d..e54c5db4f0edb 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 47acece7aa25d7b5edfae0bfd4b94e6e55a7b4b0 +Subproject commit e54c5db4f0edbe51db42d2c3e63e9821537ed4f4 diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 7586f5aa3b53b..0d4a755551a7e 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -28,7 +28,7 @@ 'rls': {'Xanewok'}, 'rustfmt': {'topecongiro', 'calebcartwright'}, 'book': {'carols10cents', 'steveklabnik'}, - 'nomicon': {'frewsxcv', 'Gankra'}, + 'nomicon': {'frewsxcv', 'Gankra', 'JohnTitor'}, 'reference': {'steveklabnik', 'Havvy', 'matthewjasper', 'ehuss'}, 'rust-by-example': {'steveklabnik', 'marioidival'}, 'embedded-book': {'adamgreig', 'andre-richter', 'jamesmunns', 'therealprof'},