From 1a26404f10d48b80c8d1ca355266ff7a3182339d Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 2 May 2024 16:28:49 +1000 Subject: [PATCH 1/9] coverage: Separately compute the set of BCBs with counter mappings --- .../src/coverage/mappings.rs | 84 +++++++++++-------- .../rustc_mir_transform/src/coverage/mod.rs | 21 +++-- 2 files changed, 59 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index ddbe1333c4b08..b2f996e2df78f 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -53,7 +53,6 @@ pub(super) struct MCDCDecision { } pub(super) struct CoverageSpans { - bcb_has_mappings: BitSet, pub(super) code_mappings: Vec, pub(super) branch_pairs: Vec, test_vector_bitmap_bytes: u32, @@ -62,10 +61,6 @@ pub(super) struct CoverageSpans { } impl CoverageSpans { - pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool { - self.bcb_has_mappings.contains(bcb) - } - pub(super) fn test_vector_bitmap_bytes(&self) -> u32 { self.test_vector_bitmap_bytes } @@ -73,13 +68,11 @@ impl CoverageSpans { /// Extracts coverage-relevant spans from MIR, and associates them with /// their corresponding BCBs. -/// -/// Returns `None` if no coverage-relevant spans could be extracted. pub(super) fn generate_coverage_spans( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, -) -> Option { +) -> CoverageSpans { let mut code_mappings = vec![]; let mut branch_pairs = vec![]; let mut mcdc_branches = vec![]; @@ -107,32 +100,6 @@ pub(super) fn generate_coverage_spans( ); } - if code_mappings.is_empty() - && branch_pairs.is_empty() - && mcdc_branches.is_empty() - && mcdc_decisions.is_empty() - { - return None; - } - - // Identify which BCBs have one or more mappings. - let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - let mut insert = |bcb| { - bcb_has_mappings.insert(bcb); - }; - - for &CodeMapping { span: _, bcb } in &code_mappings { - insert(bcb); - } - for &BranchPair { true_bcb, false_bcb, .. } in &branch_pairs { - insert(true_bcb); - insert(false_bcb); - } - for &MCDCBranch { true_bcb, false_bcb, .. } in &mcdc_branches { - insert(true_bcb); - insert(false_bcb); - } - // Determine the length of the test vector bitmap. let test_vector_bitmap_bytes = mcdc_decisions .iter() @@ -142,14 +109,57 @@ pub(super) fn generate_coverage_spans( .max() .unwrap_or(0); - Some(CoverageSpans { - bcb_has_mappings, + CoverageSpans { code_mappings, branch_pairs, test_vector_bitmap_bytes, mcdc_branches, mcdc_decisions, - }) + } +} + +impl CoverageSpans { + pub(super) fn all_bcbs_with_counter_mappings( + &self, + basic_coverage_blocks: &CoverageGraph, // Only used for allocating a correctly-sized set + ) -> BitSet { + // Fully destructure self to make sure we don't miss any fields that have mappings. + let Self { + code_mappings, + branch_pairs, + test_vector_bitmap_bytes: _, + mcdc_branches, + mcdc_decisions, + } = self; + + // Identify which BCBs have one or more mappings. + let mut bcbs_with_counter_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes()); + let mut insert = |bcb| { + bcbs_with_counter_mappings.insert(bcb); + }; + + for &CodeMapping { span: _, bcb } in code_mappings { + insert(bcb); + } + for &BranchPair { true_bcb, false_bcb, .. } in branch_pairs { + insert(true_bcb); + insert(false_bcb); + } + for &MCDCBranch { true_bcb, false_bcb, .. } in mcdc_branches { + insert(true_bcb); + insert(false_bcb); + } + + // MC/DC decisions refer to BCBs, but don't require those BCBs to have counters. + if bcbs_with_counter_mappings.is_empty() { + debug_assert!( + mcdc_decisions.is_empty(), + "A function with no counter mappings shouldn't have any decisions: {mcdc_decisions:?}", + ); + } + + bcbs_with_counter_mappings + } } fn resolve_block_markers( diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 1e2599e78e9e1..5cc01b4c9b850 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -70,21 +70,24 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: //////////////////////////////////////////////////// // Compute coverage spans from the `CoverageGraph`. - let Some(coverage_spans) = - mappings::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks) - else { - // No relevant spans were found in MIR, so skip instrumenting this function. - return; - }; + let coverage_spans = + mappings::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks); //////////////////////////////////////////////////// // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock` // and all `Expression` dependencies (operands) are also generated, for any other // `BasicCoverageBlock`s not already associated with a coverage span. - let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb); + let bcbs_with_counter_mappings = + coverage_spans.all_bcbs_with_counter_mappings(&basic_coverage_blocks); + if bcbs_with_counter_mappings.is_empty() { + // No relevant spans were found in MIR, so skip instrumenting this function. + return; + } + + let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings.contains(bcb); let coverage_counters = - CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans); + CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_counter_mappings); let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &coverage_counters); if mappings.is_empty() { @@ -96,7 +99,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: inject_coverage_statements( mir_body, &basic_coverage_blocks, - bcb_has_coverage_spans, + bcb_has_counter_mappings, &coverage_counters, ); From 496ae1ee1c6c9bbd820607e8b53c91f95e26ffdc Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 2 May 2024 20:24:23 +1000 Subject: [PATCH 2/9] coverage: Make the special case for async functions exit early --- .../src/coverage/mappings.rs | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index b2f996e2df78f..9695e39d23e07 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -52,6 +52,7 @@ pub(super) struct MCDCDecision { pub(super) decision_depth: u16, } +#[derive(Default)] pub(super) struct CoverageSpans { pub(super) code_mappings: Vec, pub(super) branch_pairs: Vec, @@ -73,33 +74,35 @@ pub(super) fn generate_coverage_spans( hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, ) -> CoverageSpans { - let mut code_mappings = vec![]; - let mut branch_pairs = vec![]; - let mut mcdc_branches = vec![]; - let mut mcdc_decisions = vec![]; - if hir_info.is_async_fn { // An async function desugars into a function that returns a future, // with the user code wrapped in a closure. Any spans in the desugared // outer function will be unhelpful, so just keep the signature span // and ignore all of the spans in the MIR body. + let mut mappings = CoverageSpans::default(); if let Some(span) = hir_info.fn_sig_span_extended { - code_mappings.push(CodeMapping { span, bcb: START_BCB }); + mappings.code_mappings.push(CodeMapping { span, bcb: START_BCB }); } - } else { - extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings); - - branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks)); - - extract_mcdc_mappings( - mir_body, - hir_info.body_span, - basic_coverage_blocks, - &mut mcdc_branches, - &mut mcdc_decisions, - ); + return mappings; } + let mut code_mappings = vec![]; + let mut branch_pairs = vec![]; + let mut mcdc_branches = vec![]; + let mut mcdc_decisions = vec![]; + + extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings); + + branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks)); + + extract_mcdc_mappings( + mir_body, + hir_info.body_span, + basic_coverage_blocks, + &mut mcdc_branches, + &mut mcdc_decisions, + ); + // Determine the length of the test vector bitmap. let test_vector_bitmap_bytes = mcdc_decisions .iter() From 83852d9bf359a886f2126504f929cfde3f17e62b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 2 May 2024 19:53:03 +1000 Subject: [PATCH 3/9] coverage: Don't recompute the number of test vector bitmap bytes The code in `extract_mcdc_mappings` that allocates these bytes already knows how many are needed in total, so there's no need to immediately recompute that value in the calling function. --- .../src/coverage/mappings.rs | 39 ++++++------------- .../rustc_mir_transform/src/coverage/mod.rs | 6 +-- 2 files changed, 12 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 9695e39d23e07..3df9579d9d0b2 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -56,17 +56,11 @@ pub(super) struct MCDCDecision { pub(super) struct CoverageSpans { pub(super) code_mappings: Vec, pub(super) branch_pairs: Vec, - test_vector_bitmap_bytes: u32, + pub(super) mcdc_bitmap_bytes: u32, pub(super) mcdc_branches: Vec, pub(super) mcdc_decisions: Vec, } -impl CoverageSpans { - pub(super) fn test_vector_bitmap_bytes(&self) -> u32 { - self.test_vector_bitmap_bytes - } -} - /// Extracts coverage-relevant spans from MIR, and associates them with /// their corresponding BCBs. pub(super) fn generate_coverage_spans( @@ -88,6 +82,7 @@ pub(super) fn generate_coverage_spans( let mut code_mappings = vec![]; let mut branch_pairs = vec![]; + let mut mcdc_bitmap_bytes = 0; let mut mcdc_branches = vec![]; let mut mcdc_decisions = vec![]; @@ -99,26 +94,12 @@ pub(super) fn generate_coverage_spans( mir_body, hir_info.body_span, basic_coverage_blocks, + &mut mcdc_bitmap_bytes, &mut mcdc_branches, &mut mcdc_decisions, ); - // Determine the length of the test vector bitmap. - let test_vector_bitmap_bytes = mcdc_decisions - .iter() - .map(|&MCDCDecision { bitmap_idx, conditions_num, .. }| { - bitmap_idx + (1_u32 << u32::from(conditions_num)).div_ceil(8) - }) - .max() - .unwrap_or(0); - - CoverageSpans { - code_mappings, - branch_pairs, - test_vector_bitmap_bytes, - mcdc_branches, - mcdc_decisions, - } + CoverageSpans { code_mappings, branch_pairs, mcdc_bitmap_bytes, mcdc_branches, mcdc_decisions } } impl CoverageSpans { @@ -130,7 +111,7 @@ impl CoverageSpans { let Self { code_mappings, branch_pairs, - test_vector_bitmap_bytes: _, + mcdc_bitmap_bytes: _, mcdc_branches, mcdc_decisions, } = self; @@ -228,6 +209,7 @@ pub(super) fn extract_mcdc_mappings( mir_body: &mir::Body<'_>, body_span: Span, basic_coverage_blocks: &CoverageGraph, + mcdc_bitmap_bytes: &mut u32, mcdc_branches: &mut impl Extend, mcdc_decisions: &mut impl Extend, ) { @@ -266,8 +248,6 @@ pub(super) fn extract_mcdc_mappings( }, )); - let mut next_bitmap_idx = 0; - mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map( |decision: &mir::coverage::MCDCDecisionSpan| { let (span, _) = unexpand_into_body_span_with_visible_macro(decision.span, body_span)?; @@ -278,8 +258,11 @@ pub(super) fn extract_mcdc_mappings( .map(|&marker| bcb_from_marker(marker)) .collect::>()?; - let bitmap_idx = next_bitmap_idx; - next_bitmap_idx += (1_u32 << decision.conditions_num).div_ceil(8); + // Each decision containing N conditions needs 2^N bits of space in + // the bitmap, rounded up to a whole number of bytes. + // The decision's "bitmap index" points to its first byte in the bitmap. + let bitmap_idx = *mcdc_bitmap_bytes; + *mcdc_bitmap_bytes += (1_u32 << decision.conditions_num).div_ceil(8); Some(MCDCDecision { span, diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 5cc01b4c9b850..572502bc7bb00 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -115,7 +115,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { function_source_hash: hir_info.function_source_hash, num_counters: coverage_counters.num_counters(), - mcdc_bitmap_bytes: coverage_spans.test_vector_bitmap_bytes(), + mcdc_bitmap_bytes: coverage_spans.mcdc_bitmap_bytes, expressions: coverage_counters.into_expressions(), mappings, mcdc_num_condition_bitmaps, @@ -254,10 +254,6 @@ fn inject_mcdc_statements<'tcx>( basic_coverage_blocks: &CoverageGraph, coverage_spans: &CoverageSpans, ) { - if coverage_spans.test_vector_bitmap_bytes() == 0 { - return; - } - // Inject test vector update first because `inject_statement` always insert new statement at head. for &mappings::MCDCDecision { span: _, From 84cedbec9dc007deca85d226097624ec1bf5ee4e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 2 May 2024 16:45:23 +1000 Subject: [PATCH 4/9] coverage: Destructure the mappings struct to make sure we don't miss any --- .../rustc_mir_transform/src/coverage/mod.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 572502bc7bb00..3666aad3fadf4 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -151,9 +151,18 @@ fn create_mappings<'tcx>( }; let region_for_span = |span: Span| make_code_region(source_map, file_name, span, body_span); + // Fully destructure the mappings struct to make sure we don't miss any kinds. + let CoverageSpans { + code_mappings, + branch_pairs, + mcdc_bitmap_bytes: _, + mcdc_branches, + mcdc_decisions, + } = coverage_spans; let mut mappings = Vec::new(); - mappings.extend(coverage_spans.code_mappings.iter().filter_map( + mappings.extend(code_mappings.iter().filter_map( + // Ordinary code mappings are the simplest kind. |&mappings::CodeMapping { span, bcb }| { let code_region = region_for_span(span)?; let kind = MappingKind::Code(term_for_bcb(bcb)); @@ -161,7 +170,7 @@ fn create_mappings<'tcx>( }, )); - mappings.extend(coverage_spans.branch_pairs.iter().filter_map( + mappings.extend(branch_pairs.iter().filter_map( |&mappings::BranchPair { span, true_bcb, false_bcb }| { let true_term = term_for_bcb(true_bcb); let false_term = term_for_bcb(false_bcb); @@ -171,7 +180,7 @@ fn create_mappings<'tcx>( }, )); - mappings.extend(coverage_spans.mcdc_branches.iter().filter_map( + mappings.extend(mcdc_branches.iter().filter_map( |&mappings::MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth: _ }| { let code_region = region_for_span(span)?; let true_term = term_for_bcb(true_bcb); @@ -184,7 +193,7 @@ fn create_mappings<'tcx>( }, )); - mappings.extend(coverage_spans.mcdc_decisions.iter().filter_map( + mappings.extend(mcdc_decisions.iter().filter_map( |&mappings::MCDCDecision { span, bitmap_idx, conditions_num, .. }| { let code_region = region_for_span(span)?; let kind = MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, conditions_num }); From 56c6288c6f3264e1300a36636814365fdafac871 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 2 May 2024 17:05:32 +1000 Subject: [PATCH 5/9] coverage: Rename `CoverageSpans` to `ExtractedMappings` --- .../src/coverage/mappings.rs | 18 +++++++---- .../rustc_mir_transform/src/coverage/mod.rs | 30 +++++++++---------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 3df9579d9d0b2..61aabea1d8b31 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -53,7 +53,7 @@ pub(super) struct MCDCDecision { } #[derive(Default)] -pub(super) struct CoverageSpans { +pub(super) struct ExtractedMappings { pub(super) code_mappings: Vec, pub(super) branch_pairs: Vec, pub(super) mcdc_bitmap_bytes: u32, @@ -63,17 +63,17 @@ pub(super) struct CoverageSpans { /// Extracts coverage-relevant spans from MIR, and associates them with /// their corresponding BCBs. -pub(super) fn generate_coverage_spans( +pub(super) fn extract_all_mapping_info_from_mir( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, -) -> CoverageSpans { +) -> ExtractedMappings { if hir_info.is_async_fn { // An async function desugars into a function that returns a future, // with the user code wrapped in a closure. Any spans in the desugared // outer function will be unhelpful, so just keep the signature span // and ignore all of the spans in the MIR body. - let mut mappings = CoverageSpans::default(); + let mut mappings = ExtractedMappings::default(); if let Some(span) = hir_info.fn_sig_span_extended { mappings.code_mappings.push(CodeMapping { span, bcb: START_BCB }); } @@ -99,10 +99,16 @@ pub(super) fn generate_coverage_spans( &mut mcdc_decisions, ); - CoverageSpans { code_mappings, branch_pairs, mcdc_bitmap_bytes, mcdc_branches, mcdc_decisions } + ExtractedMappings { + code_mappings, + branch_pairs, + mcdc_bitmap_bytes, + mcdc_branches, + mcdc_decisions, + } } -impl CoverageSpans { +impl ExtractedMappings { pub(super) fn all_bcbs_with_counter_mappings( &self, basic_coverage_blocks: &CoverageGraph, // Only used for allocating a correctly-sized set diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 3666aad3fadf4..ed3fd889917f0 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -9,7 +9,7 @@ mod tests; use self::counters::{CounterIncrementSite, CoverageCounters}; use self::graph::{BasicCoverageBlock, CoverageGraph}; -use self::mappings::CoverageSpans; +use self::mappings::ExtractedMappings; use crate::MirPass; @@ -69,9 +69,9 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); //////////////////////////////////////////////////// - // Compute coverage spans from the `CoverageGraph`. - let coverage_spans = - mappings::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks); + // Extract coverage spans and other mapping info from MIR. + let extracted_mappings = + mappings::extract_all_mapping_info_from_mir(mir_body, &hir_info, &basic_coverage_blocks); //////////////////////////////////////////////////// // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure @@ -79,7 +79,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: // and all `Expression` dependencies (operands) are also generated, for any other // `BasicCoverageBlock`s not already associated with a coverage span. let bcbs_with_counter_mappings = - coverage_spans.all_bcbs_with_counter_mappings(&basic_coverage_blocks); + extracted_mappings.all_bcbs_with_counter_mappings(&basic_coverage_blocks); if bcbs_with_counter_mappings.is_empty() { // No relevant spans were found in MIR, so skip instrumenting this function. return; @@ -89,7 +89,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: let coverage_counters = CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_counter_mappings); - let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &coverage_counters); + let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &coverage_counters); if mappings.is_empty() { // No spans could be converted into valid mappings, so skip this function. debug!("no spans could be converted into valid mappings; skipping"); @@ -103,9 +103,9 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: &coverage_counters, ); - inject_mcdc_statements(mir_body, &basic_coverage_blocks, &coverage_spans); + inject_mcdc_statements(mir_body, &basic_coverage_blocks, &extracted_mappings); - let mcdc_num_condition_bitmaps = coverage_spans + let mcdc_num_condition_bitmaps = extracted_mappings .mcdc_decisions .iter() .map(|&mappings::MCDCDecision { decision_depth, .. }| decision_depth) @@ -115,7 +115,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { function_source_hash: hir_info.function_source_hash, num_counters: coverage_counters.num_counters(), - mcdc_bitmap_bytes: coverage_spans.mcdc_bitmap_bytes, + mcdc_bitmap_bytes: extracted_mappings.mcdc_bitmap_bytes, expressions: coverage_counters.into_expressions(), mappings, mcdc_num_condition_bitmaps, @@ -130,7 +130,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: fn create_mappings<'tcx>( tcx: TyCtxt<'tcx>, hir_info: &ExtractedHirInfo, - coverage_spans: &CoverageSpans, + extracted_mappings: &ExtractedMappings, coverage_counters: &CoverageCounters, ) -> Vec { let source_map = tcx.sess.source_map(); @@ -152,13 +152,13 @@ fn create_mappings<'tcx>( let region_for_span = |span: Span| make_code_region(source_map, file_name, span, body_span); // Fully destructure the mappings struct to make sure we don't miss any kinds. - let CoverageSpans { + let ExtractedMappings { code_mappings, branch_pairs, mcdc_bitmap_bytes: _, mcdc_branches, mcdc_decisions, - } = coverage_spans; + } = extracted_mappings; let mut mappings = Vec::new(); mappings.extend(code_mappings.iter().filter_map( @@ -261,7 +261,7 @@ fn inject_coverage_statements<'tcx>( fn inject_mcdc_statements<'tcx>( mir_body: &mut mir::Body<'tcx>, basic_coverage_blocks: &CoverageGraph, - coverage_spans: &CoverageSpans, + extracted_mappings: &ExtractedMappings, ) { // Inject test vector update first because `inject_statement` always insert new statement at head. for &mappings::MCDCDecision { @@ -270,7 +270,7 @@ fn inject_mcdc_statements<'tcx>( bitmap_idx, conditions_num: _, decision_depth, - } in &coverage_spans.mcdc_decisions + } in &extracted_mappings.mcdc_decisions { for end in end_bcbs { let end_bb = basic_coverage_blocks[*end].leader_bb(); @@ -283,7 +283,7 @@ fn inject_mcdc_statements<'tcx>( } for &mappings::MCDCBranch { span: _, true_bcb, false_bcb, condition_info, decision_depth } in - &coverage_spans.mcdc_branches + &extracted_mappings.mcdc_branches { let Some(condition_info) = condition_info else { continue }; let id = condition_info.condition_id; From 0c12a3b1d4f9d6b742abd03a05b20cb5bd3d73c1 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 2 May 2024 17:32:18 +1000 Subject: [PATCH 6/9] coverage: Tidy imports in `rustc_mir_transform::coverage` --- compiler/rustc_mir_transform/src/coverage/mod.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index ed3fd889917f0..28e0c633d5aaa 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -7,13 +7,9 @@ mod spans; #[cfg(test)] mod tests; -use self::counters::{CounterIncrementSite, CoverageCounters}; -use self::graph::{BasicCoverageBlock, CoverageGraph}; -use self::mappings::ExtractedMappings; - -use crate::MirPass; - -use rustc_middle::mir::coverage::*; +use rustc_middle::mir::coverage::{ + CodeRegion, CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind, +}; use rustc_middle::mir::{ self, BasicBlock, BasicBlockData, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, @@ -23,6 +19,11 @@ use rustc_span::def_id::LocalDefId; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol}; +use crate::coverage::counters::{CounterIncrementSite, CoverageCounters}; +use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; +use crate::coverage::mappings::ExtractedMappings; +use crate::MirPass; + /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen /// to construct the coverage map. From d50c2b0a52f31fbbf6e6bfa27c129b513fdddb0b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 9 May 2024 22:45:14 -0400 Subject: [PATCH 7/9] Make builtin_deref just return a Ty --- .../src/diagnostics/mutability_errors.rs | 5 +-- compiler/rustc_borrowck/src/type_check/mod.rs | 4 +- compiler/rustc_codegen_cranelift/src/base.rs | 7 +--- .../src/intrinsics/mod.rs | 6 +-- .../src/intrinsics/simd.rs | 2 +- compiler/rustc_codegen_cranelift/src/lib.rs | 2 +- compiler/rustc_codegen_cranelift/src/num.rs | 10 ++--- .../rustc_codegen_cranelift/src/unsize.rs | 2 +- .../src/value_and_place.rs | 2 +- .../rustc_codegen_cranelift/src/vtable.rs | 2 +- compiler/rustc_codegen_llvm/src/abi.rs | 2 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 6 +-- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 3 +- .../src/const_eval/eval_queries.rs | 2 +- .../src/interpret/intrinsics.rs | 6 +-- .../src/interpret/operator.rs | 2 +- .../rustc_const_eval/src/interpret/place.rs | 2 +- .../src/transform/validate.rs | 4 +- .../src/util/check_validity_requirement.rs | 2 +- compiler/rustc_hir_analysis/src/autoderef.rs | 41 +++++++++---------- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 5 +-- .../src/mem_categorization.rs | 4 +- compiler/rustc_hir_typeck/src/pat.rs | 4 +- compiler/rustc_hir_typeck/src/place_op.rs | 11 +++-- compiler/rustc_middle/src/mir/tcx.rs | 10 ++--- compiler/rustc_middle/src/ty/sty.rs | 12 +++--- .../src/check_alignment.rs | 2 +- .../src/dataflow_const_prop.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 6 +-- .../src/mentioned_items.rs | 4 +- .../src/normalize_array_len.rs | 4 +- compiler/rustc_symbol_mangling/src/v0.rs | 3 +- .../matches/significant_drop_in_scrutinee.rs | 8 ++-- .../clippy_lints/src/operators/cmp_owned.rs | 2 +- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- .../src/borrow_tracker/stacked_borrows/mod.rs | 2 +- .../src/borrow_tracker/tree_borrows/mod.rs | 2 +- src/tools/miri/src/intrinsics/mod.rs | 2 +- src/tools/miri/src/intrinsics/simd.rs | 2 +- .../miri/src/shims/unix/foreign_items.rs | 3 +- 43 files changed, 92 insertions(+), 116 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 5d74a01aa2076..9631c7de9ff10 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1483,10 +1483,9 @@ fn suggest_ampmut<'tcx>( } else { // otherwise, suggest that the user annotates the binding; we provide the // type of the local. - let ty_mut = decl_ty.builtin_deref(true).unwrap(); - assert_eq!(ty_mut.mutbl, hir::Mutability::Not); + let ty = decl_ty.builtin_deref(true).unwrap(); - (false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty_mut.ty)) + (false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty)) } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 13acc672defb8..3cc8099982c6b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -401,7 +401,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity(); let normalized_ty = self.cx.normalize(unnormalized_ty, locations); - let literal_ty = constant.const_.ty().builtin_deref(true).unwrap().ty; + let literal_ty = constant.const_.ty().builtin_deref(true).unwrap(); if let Err(terr) = self.cx.eq_types( literal_ty, @@ -638,7 +638,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { match pi { ProjectionElem::Deref => { let deref_ty = base_ty.builtin_deref(true); - PlaceTy::from_ty(deref_ty.map(|t| t.ty).unwrap_or_else(|| { + PlaceTy::from_ty(deref_ty.unwrap_or_else(|| { span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty) })) } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index e3d050df4cd1b..8874efadec9d9 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -670,11 +670,8 @@ fn codegen_stmt<'tcx>( let to_ty = fx.monomorphize(to_ty); fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.builtin_deref(true).is_some_and( - |ty::TypeAndMut { ty: pointee_ty, mutbl: _ }| { - has_ptr_meta(fx.tcx, pointee_ty) - }, - ) + ty.builtin_deref(true) + .is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty)) } if is_fat_ptr(fx, from_ty) { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 79a90507fa2e1..cafdc051db5ac 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -586,7 +586,7 @@ fn codegen_regular_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (base, offset); intrinsic); let offset = offset.load_scalar(fx); - let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty; + let pointee_ty = base.layout().ty.builtin_deref(true).unwrap(); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let ptr_diff = if pointee_size != 1 { fx.bcx.ins().imul_imm(offset, pointee_size as i64) @@ -610,7 +610,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = val.load_scalar(fx); let count = count.load_scalar(fx); - let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap().ty; + let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap(); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let count = if pointee_size != 1 { fx.bcx.ins().imul_imm(count, pointee_size as i64) @@ -715,7 +715,7 @@ fn codegen_regular_intrinsic_call<'tcx>( // Cranelift treats loads as volatile by default // FIXME correctly handle unaligned_volatile_load - let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty); + let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap()); let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), inner_layout); ret.write_cvalue(fx, val); } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 67f9d83106294..452b5988dab4c 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -974,7 +974,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (ptr, offset); intrinsic); let (lane_count, ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx); - let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap().ty; + let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap(); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); let ret_lane_layout = fx.layout_of(ret_lane_ty); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index c9f84b6999718..e72951b6f3447 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -95,7 +95,7 @@ mod prelude { pub(crate) use rustc_middle::mir::{self, *}; pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; pub(crate) use rustc_middle::ty::{ - self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, UintTy, + self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, UintTy, }; pub(crate) use rustc_span::Span; pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT}; diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index 714858084ec9d..4d96a26ea4fa8 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -388,12 +388,8 @@ pub(crate) fn codegen_ptr_binop<'tcx>( in_lhs: CValue<'tcx>, in_rhs: CValue<'tcx>, ) -> CValue<'tcx> { - let is_thin_ptr = in_lhs - .layout() - .ty - .builtin_deref(true) - .map(|TypeAndMut { ty, mutbl: _ }| !has_ptr_meta(fx.tcx, ty)) - .unwrap_or(true); + let is_thin_ptr = + in_lhs.layout().ty.builtin_deref(true).map(|ty| !has_ptr_meta(fx.tcx, ty)).unwrap_or(true); if is_thin_ptr { match bin_op { @@ -404,7 +400,7 @@ pub(crate) fn codegen_ptr_binop<'tcx>( codegen_compare_bin_op(fx, bin_op, false, lhs, rhs) } BinOp::Offset => { - let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap().ty; + let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap(); let (base, offset) = (in_lhs, in_rhs.load_scalar(fx)); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64); diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index f33bacb99a3fa..4acbc8a27edb9 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -127,7 +127,7 @@ pub(crate) fn coerce_unsized_into<'tcx>( let dst_ty = dst.layout().ty; let mut coerce_ptr = || { let (base, info) = - if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap().ty).is_unsized() { + if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap()).is_unsized() { let (old_base, old_info) = src.load_scalar_pair(fx); unsize_ptr(fx, old_base, src.layout(), dst.layout(), Some(old_info)) } else { diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index dded6df7771df..a11abd0c0e978 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -819,7 +819,7 @@ impl<'tcx> CPlace<'tcx> { } pub(crate) fn place_deref(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> CPlace<'tcx> { - let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap().ty); + let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap()); if has_ptr_meta(fx.tcx, inner_layout.ty) { let (addr, extra) = self.to_cvalue(fx).load_scalar_pair(fx); CPlace::for_ptr_with_extra(Pointer::new(addr), extra, inner_layout) diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 04e24320f9131..14c607ccad7d7 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -59,7 +59,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( if let ty::Ref(_, ty, _) = arg.layout().ty.kind() { if ty.is_dyn_star() { - let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap().ty); + let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap()); let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout); let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr(); let vtable = diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 123aef0f31076..a6a3f0f964611 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -583,7 +583,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { let element_type_index = unsafe { llvm::LLVMRustGetElementTypeArgIndex(callsite) }; if element_type_index >= 0 { let arg_ty = self.args[element_type_index as usize].layout.ty; - let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument").ty; + let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument"); let element_type_attr = unsafe { llvm::LLVMRustCreateElementTypeAttr(bx.llcx, bx.layout_of(pointee_ty).llvm_type(bx)) }; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 56550dbfa4b8b..1376a92652655 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -2383,7 +2383,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| { span_bug!(span, "must be called with a vector of pointer types as first argument") }); - let layout = bx.layout_of(pointee.ty); + let layout = bx.layout_of(pointee); let ptrs = args[0].immediate(); // The second argument must be a ptr-sized integer. // (We don't care about the signedness, this is wrapping anyway.) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 2f57695ac290e..d36972d0d8662 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1060,7 +1060,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Make sure that we've actually unwrapped the rcvr down // to a pointer or ref to `dyn* Trait`. - if !op.layout.ty.builtin_deref(true).unwrap().ty.is_dyn_star() { + if !op.layout.ty.builtin_deref(true).unwrap().is_dyn_star() { span_bug!(span, "can't codegen a virtual call on {:#?}", op); } let place = op.deref(bx.cx()); diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 50bf1ef61f3a4..6b89636b6540c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -120,7 +120,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> { fn deref(&self, bx: &mut Bx) -> Self { bx.cx().layout_of( - self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)).ty, + self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)), ) } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 38f77f2e646fc..a2fce1275c25e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -215,8 +215,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { .layout .ty .builtin_deref(true) - .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)) - .ty; + .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)); let (llptr, llextra) = match self.val { OperandValue::Immediate(llptr) => (llptr, None), @@ -455,8 +454,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { .layout .ty .builtin_deref(true) - .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)) - .ty; + .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)); let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self else { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 4e7d251a2e928..06ed569b10297 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -870,8 +870,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::BinOp::Offset => { let pointee_type = input_ty .builtin_deref(true) - .unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty)) - .ty; + .unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty)); let pointee_layout = bx.cx().layout_of(pointee_type); if pointee_layout.is_zst() { // `Offset` works in terms of the size of pointee, diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 71a41e9cfe410..d9f329c8b0e0f 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -222,7 +222,7 @@ pub(super) fn op_to_const<'tcx>( // This codepath solely exists for `valtree_to_const_value` to not need to generate // a `ConstValue::Indirect` for wide references, so it is tightly restricted to just // that case. - let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap().ty; // `false` = no raw ptrs + let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs debug_assert!( matches!( ecx.tcx.struct_tail_without_normalization(pointee_ty).kind(), diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 88ce5a7cbebba..9fbf2820d12cc 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -602,7 +602,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { nonoverlapping: bool, ) -> InterpResult<'tcx> { let count = self.read_target_usize(count)?; - let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?; + let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap())?; let (size, align) = (layout.size, layout.align.abi); // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), // but no actual allocation can be big enough for the difference to be noticeable. @@ -646,7 +646,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { byte: &OpTy<'tcx, >::Provenance>, count: &OpTy<'tcx, >::Provenance>, ) -> InterpResult<'tcx> { - let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?; + let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap())?; let dst = self.read_pointer(dst)?; let byte = self.read_scalar(byte)?.to_u8()?; @@ -685,7 +685,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { lhs: &OpTy<'tcx, >::Provenance>, rhs: &OpTy<'tcx, >::Provenance>, ) -> InterpResult<'tcx, Scalar> { - let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?; + let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap())?; assert!(layout.is_sized()); let get_bytes = |this: &InterpCx<'mir, 'tcx, M>, diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 9af755e40de87..2d5dbbd58b3b0 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -357,7 +357,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Offset => { let ptr = left.to_scalar().to_pointer(self)?; let offset_count = right.to_scalar().to_target_isize(self)?; - let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; + let pointee_ty = left.layout.ty.builtin_deref(true).unwrap(); // We cannot overflow i64 as a type's size must be <= isize::MAX. let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index e5241f1ba19e1..809aca18990f8 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -415,7 +415,7 @@ where val: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { let pointee_type = - val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; + val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type"); let layout = self.layout_of(pointee_type)?; let (ptr, meta) = val.to_scalar_and_meta(); diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 837c02a5b769b..c95166d84e933 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -1291,7 +1291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { )) => { let src_ty = src.ty(&self.body.local_decls, self.tcx); let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) { - src_deref.ty + src_deref } else { self.fail( location, @@ -1301,7 +1301,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; let dst_ty = dst.ty(&self.body.local_decls, self.tcx); let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) { - dst_deref.ty + dst_deref } else { self.fail( location, diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 8c4af5e513217..36597507f4747 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -115,7 +115,7 @@ fn might_permit_raw_init_lax<'tcx>( // Special magic check for references and boxes (i.e., special pointer types). if let Some(pointee) = this.ty.builtin_deref(false) { - let pointee = cx.layout_of(pointee.ty)?; + let pointee = cx.layout_of(pointee)?; // We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied. if pointee.align.abi.bytes() > 1 { // 0x01-filling is not aligned. diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index f101c595bdf35..2bf14a2461f31 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -68,28 +68,27 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { } // Otherwise, deref if type is derefable: - let (kind, new_ty) = if let Some(ty::TypeAndMut { ty, .. }) = - self.state.cur_ty.builtin_deref(self.include_raw_pointers) - { - debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); - // NOTE: we may still need to normalize the built-in deref in case - // we have some type like `&::Assoc`, since users of - // autoderef expect this type to have been structurally normalized. - if self.infcx.next_trait_solver() - && let ty::Alias(..) = ty.kind() - { - let (normalized_ty, obligations) = self.structurally_normalize(ty)?; - self.state.obligations.extend(obligations); - (AutoderefKind::Builtin, normalized_ty) + let (kind, new_ty) = + if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) { + debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); + // NOTE: we may still need to normalize the built-in deref in case + // we have some type like `&::Assoc`, since users of + // autoderef expect this type to have been structurally normalized. + if self.infcx.next_trait_solver() + && let ty::Alias(..) = ty.kind() + { + let (normalized_ty, obligations) = self.structurally_normalize(ty)?; + self.state.obligations.extend(obligations); + (AutoderefKind::Builtin, normalized_ty) + } else { + (AutoderefKind::Builtin, ty) + } + } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + // The overloaded deref check already normalizes the pointee type. + (AutoderefKind::Overloaded, ty) } else { - (AutoderefKind::Builtin, ty) - } - } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { - // The overloaded deref check already normalizes the pointee type. - (AutoderefKind::Overloaded, ty) - } else { - return None; - }; + return None; + }; self.state.steps.push((self.state.cur_ty, kind)); debug!( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 552747bdc5272..f2091c5aee3a2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -624,10 +624,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// returns a type of `&T`, but the actual type we assign to the /// *expression* is `T`. So this function just peels off the return /// type by one layer to yield `T`. - pub(crate) fn make_overloaded_place_return_type( - &self, - method: MethodCallee<'tcx>, - ) -> ty::TypeAndMut<'tcx> { + pub(crate) fn make_overloaded_place_return_type(&self, method: MethodCallee<'tcx>) -> Ty<'tcx> { // extract method return type, which will be &T; let ret_ty = method.sig.output(); diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index b44c2345933fb..ae71c484f7b04 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -207,7 +207,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // but what we want here is the type of the underlying value being borrowed. // So peel off one-level, turning the &T into T. match base_ty.builtin_deref(false) { - Some(t) => Ok(t.ty), + Some(ty) => Ok(ty), None => { debug!("By-ref binding of non-derefable type"); Err(()) @@ -485,7 +485,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ) -> McResult> { let base_curr_ty = base_place.place.ty(); let deref_ty = match base_curr_ty.builtin_deref(true) { - Some(mt) => mt.ty, + Some(pointee_ty) => pointee_ty, None => { debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); return Err(()); diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 8c7ae7f8e980d..38fd2d35b317a 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -919,8 +919,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &Pat<'_>, ) -> Result<(), ErrorGuaranteed> { if let PatKind::Binding(..) = inner.kind - && let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) - && let ty::Dynamic(..) = mt.ty.kind() + && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true) + && let ty::Dynamic(..) = pointee_ty.kind() { // This is "x = dyn SomeTrait" being reduced from // "let &x = &dyn SomeTrait" or "let box x = Box", an error. diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index bce43b3be3434..3c8f0776e5dd0 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -20,8 +20,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { oprnd_expr: &'tcx hir::Expr<'tcx>, oprnd_ty: Ty<'tcx>, ) -> Option> { - if let Some(mt) = oprnd_ty.builtin_deref(true) { - return Some(mt.ty); + if let Some(ty) = oprnd_ty.builtin_deref(true) { + return Some(ty); } let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?; @@ -37,7 +37,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { span_bug!(expr.span, "input to deref is not a ref?"); } - let ty = self.make_overloaded_place_return_type(method).ty; + let ty = self.make_overloaded_place_return_type(method); self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); Some(ty) } @@ -175,7 +175,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); - return Some((input_ty, self.make_overloaded_place_return_type(method).ty)); + return Some((input_ty, self.make_overloaded_place_return_type(method))); } } @@ -344,8 +344,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .borrow() .expr_ty_adjusted(base_expr) .builtin_deref(false) - .expect("place op takes something that is not a ref") - .ty; + .expect("place op takes something that is not a ref"); let arg_ty = match op { PlaceOp::Deref => None, diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 3881723c5ec9c..4994679ad5dad 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -78,13 +78,9 @@ impl<'tcx> PlaceTy<'tcx> { } let answer = match *elem { ProjectionElem::Deref => { - let ty = self - .ty - .builtin_deref(true) - .unwrap_or_else(|| { - bug!("deref projection of non-dereferenceable ty {:?}", self) - }) - .ty; + let ty = self.ty.builtin_deref(true).unwrap_or_else(|| { + bug!("deref projection of non-dereferenceable ty {:?}", self) + }); PlaceTy::from_ty(ty) } ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index de70c4f7b65a1..32b970962e82f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2164,13 +2164,11 @@ impl<'tcx> Ty<'tcx> { /// /// The parameter `explicit` indicates if this is an *explicit* dereference. /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. - pub fn builtin_deref(self, explicit: bool) -> Option> { - match self.kind() { - Adt(def, _) if def.is_box() => { - Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not }) - } - Ref(_, ty, mutbl) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }), - RawPtr(ty, mutbl) if explicit => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }), + pub fn builtin_deref(self, explicit: bool) -> Option> { + match *self.kind() { + Adt(def, _) if def.is_box() => Some(self.boxed_ty()), + Ref(_, ty, _) => Some(ty), + RawPtr(ty, _) if explicit => Some(ty), _ => None, } } diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index 0af8872988754..5199c41c58cd4 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -106,7 +106,7 @@ impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> { } let pointee_ty = - pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer").ty; + pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer"); // Ideally we'd support this in the future, but for now we are limited to sized types. if !pointee_ty.is_sized(self.tcx, self.param_env) { debug!("Unsafe pointer, but pointee is not known to be sized: {:?}", pointer_ty); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index d0f6ec8f21f84..3019b275fb260 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -202,7 +202,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { if let Some(target_len) = self.map().find_len(target.as_ref()) && let operand_ty = operand.ty(self.local_decls, self.tcx) && let Some(operand_ty) = operand_ty.builtin_deref(true) - && let ty::Array(_, len) = operand_ty.ty.kind() + && let ty::Array(_, len) = operand_ty.kind() && let Some(len) = Const::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env) { state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map()); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 4dd595ce1e1ce..342d1a1cd5bb0 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -594,7 +594,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let ty = place.ty(self.local_decls, self.tcx).ty; if let Some(Mutability::Not) = ty.ref_mutability() && let Some(pointee_ty) = ty.builtin_deref(true) - && pointee_ty.ty.is_freeze(self.tcx, self.param_env) + && pointee_ty.is_freeze(self.tcx, self.param_env) { // An immutable borrow `_x` always points to the same value for the // lifetime of the borrow, so we can merge all instances of `*_x`. @@ -1133,9 +1133,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if let Value::Cast { kind, from, to, .. } = self.get(inner) && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind && let Some(from) = from.builtin_deref(true) - && let ty::Array(_, len) = from.ty.kind() + && let ty::Array(_, len) = from.kind() && let Some(to) = to.builtin_deref(true) - && let ty::Slice(..) = to.ty.kind() + && let ty::Slice(..) = to.kind() { return self.insert_constant(Const::from_ty_const(*len, self.tcx)); } diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs index 57b6126dece93..db2bb60bdac34 100644 --- a/compiler/rustc_mir_transform/src/mentioned_items.rs +++ b/compiler/rustc_mir_transform/src/mentioned_items.rs @@ -79,8 +79,8 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> { // add everything that may involve a vtable. let source_ty = operand.ty(self.body, self.tcx); let may_involve_vtable = match ( - source_ty.builtin_deref(true).map(|t| t.ty.kind()), - target_ty.builtin_deref(true).map(|t| t.ty.kind()), + source_ty.builtin_deref(true).map(|t| t.kind()), + target_ty.builtin_deref(true).map(|t| t.kind()), ) { (Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false, // &str/&[T] unsizing _ => true, diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index c26a54616331c..2070895c9002b 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -48,9 +48,9 @@ fn compute_slice_length<'tcx>( let operand_ty = operand.ty(body, tcx); debug!(?operand_ty); if let Some(operand_ty) = operand_ty.builtin_deref(true) - && let ty::Array(_, len) = operand_ty.ty.kind() + && let ty::Array(_, len) = operand_ty.kind() && let Some(cast_ty) = cast_ty.builtin_deref(true) - && let ty::Slice(..) = cast_ty.ty.kind() + && let ty::Slice(..) = cast_ty.kind() { slice_lengths[local] = Some(*len); } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 5cdfb773b5cb6..1de2ecbb7006d 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -630,8 +630,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { let pointee_ty = ct .ty() .builtin_deref(true) - .expect("tried to dereference on non-ptr type") - .ty; + .expect("tried to dereference on non-ptr type"); // FIXME(const_generics): add an assert that we only do this for valtrees. let dereferenced_const = self.tcx.mk_ct_from_kind(ct.kind(), pointee_ty); dereferenced_const.print(self)?; diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 10c3203725a81..f775ea072e1f0 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -6,7 +6,7 @@ use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut}; +use rustc_middle::ty::{GenericArgKind, Ty}; use rustc_span::Span; use super::SIGNIFICANT_DROP_IN_SCRUTINEE; @@ -234,9 +234,9 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { } let ty = self.sig_drop_checker.get_type(expr); if ty.is_ref() { - // We checked that the type was ref, so builtin_deref will return Some TypeAndMut, - // but let's avoid any chance of an ICE - if let Some(TypeAndMut { ty, .. }) = ty.builtin_deref(true) { + // We checked that the type was ref, so builtin_deref will return Some, + // but let's avoid any chance of an ICE. + if let Some(ty) = ty.builtin_deref(true) { if ty.is_trivially_pure_clone_copy() { self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndDerefToCopy); } else if allow_move_and_clone { diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs index ea8ed28ba62ba..208b20a7a0691 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -70,7 +70,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default(); let with_deref = arg_ty .builtin_deref(true) - .and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty)) + .and_then(|ty| symmetric_partial_eq(cx, ty, other_ty)) .unwrap_or_default(); if !with_deref.is_implemented() && !without_deref.is_implemented() { diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 325c9bee05782..d8d26e21369a4 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -134,7 +134,7 @@ fn check_rvalue<'tcx>( ) => Err((span, "function pointer casts are not allowed in const fn".into())), Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => { let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) { - deref_ty.ty + deref_ty } else { // We cannot allow this for now. return Err((span, "unsizing casts are only allowed for references right now".into())); diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index a6dd1d829cb4f..3da8744626d72 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -136,7 +136,7 @@ impl NewPermission { cx: &crate::MiriInterpCx<'_, 'tcx>, ) -> Self { // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling). - let pointee = ty.builtin_deref(true).unwrap().ty; + let pointee = ty.builtin_deref(true).unwrap(); if pointee.is_unpin(*cx.tcx, cx.param_env()) { // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only // a weak protector). diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index fc5eb942a27b5..b5bf16d3d3665 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -173,7 +173,7 @@ impl<'tcx> NewPermission { cx: &crate::MiriInterpCx<'_, 'tcx>, zero_size: bool, ) -> Option { - let pointee = ty.builtin_deref(true).unwrap().ty; + let pointee = ty.builtin_deref(true).unwrap(); pointee.is_unpin(*cx.tcx, cx.param_env()).then_some(()).map(|()| { // Regular `Unpin` box, give it `noalias` but only a weak protector // because it is valid to deallocate it within the function. diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index effd7f6d5435f..9e7fc7a21fcb4 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -117,7 +117,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "write_bytes" | "volatile_set_memory" => { let [ptr, val_byte, count] = check_arg_count(args)?; - let ty = ptr.layout.ty.builtin_deref(true).unwrap().ty; + let ty = ptr.layout.ty.builtin_deref(true).unwrap(); let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; let ptr = this.read_pointer(ptr)?; diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 3be98d7f5f864..d0a78429ca851 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -267,7 +267,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Op::WrappingOffset => { let ptr = left.to_scalar().to_pointer(this)?; let offset_count = right.to_scalar().to_target_isize(this)?; - let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; + let pointee_ty = left.layout.ty.builtin_deref(true).unwrap(); let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); let offset_bytes = offset_count.wrapping_mul(pointee_size); diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 595cf64a4e4b4..aaf47248af629 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -378,8 +378,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { .builtin_deref(true) .ok_or_else(|| err_ub_format!( "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." - ))? - .ty; + ))?; let key_layout = this.layout_of(key_type)?; // Create key and write it into the memory where `key_ptr` wants it. From 0ad3c5da72469c848e321ddee207f9a5dfbf9876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 6 May 2024 01:25:49 +0200 Subject: [PATCH 8/9] Fix parse error message for meta items --- compiler/rustc_parse/messages.ftl | 6 +- compiler/rustc_parse/src/errors.rs | 14 +---- compiler/rustc_parse/src/parser/attr.rs | 56 ++++++++++--------- tests/ui/attributes/nonterminal-expansion.rs | 2 +- .../attributes/nonterminal-expansion.stderr | 2 +- .../cfg-attr-syntax-validation.rs | 4 +- .../cfg-attr-syntax-validation.stderr | 4 +- ...40-deprecated-attr-non-meta-grammar.stderr | 2 +- tests/ui/parser/attribute/attr-bad-meta-4.rs | 9 ++- .../parser/attribute/attr-bad-meta-4.stderr | 20 ++++++- .../attribute/attr-unquoted-ident.fixed | 17 ------ .../parser/attribute/attr-unquoted-ident.rs | 14 ++++- .../attribute/attr-unquoted-ident.stderr | 21 +++++-- 13 files changed, 93 insertions(+), 78 deletions(-) delete mode 100644 tests/ui/parser/attribute/attr-unquoted-ident.fixed diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 873095dca8722..04f855e4f559b 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -401,10 +401,8 @@ parse_invalid_logical_operator = `{$incorrect}` is not a logical operator .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction -parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}` - -parse_invalid_meta_item_unquoted_ident = expected unsuffixed literal, found `{$token}` - .suggestion = surround the identifier with quotation marks to parse it as a string +parse_invalid_meta_item = expected unsuffixed literal, found `{$token}` + .quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal parse_invalid_offset_of = offset_of expects dot-separated field and variant names diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index d06f03a7c1767..2f68a299f26b6 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -978,21 +978,13 @@ pub(crate) struct InvalidMetaItem { #[primary_span] pub span: Span, pub token: Token, -} - -#[derive(Diagnostic)] -#[diag(parse_invalid_meta_item_unquoted_ident)] -pub(crate) struct InvalidMetaItemUnquotedIdent { - #[primary_span] - pub span: Span, - pub token: Token, #[subdiagnostic] - pub sugg: InvalidMetaItemSuggQuoteIdent, + pub quote_ident_sugg: Option, } #[derive(Subdiagnostic)] -#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] -pub(crate) struct InvalidMetaItemSuggQuoteIdent { +#[multipart_suggestion(parse_quote_ident_sugg, applicability = "machine-applicable")] +pub(crate) struct InvalidMetaItemQuoteIdentSugg { #[suggestion_part(code = "\"")] pub before: Span, #[suggestion_part(code = "\"")] diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index ab5f51eedc307..d5d8060d909a1 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -1,7 +1,4 @@ -use crate::errors::{ - InvalidMetaItem, InvalidMetaItemSuggQuoteIdent, InvalidMetaItemUnquotedIdent, - SuffixedLiteralInAttribute, -}; +use crate::errors; use crate::fluent_generated as fluent; use crate::maybe_whole; @@ -318,7 +315,7 @@ impl<'a> Parser<'a> { debug!("checking if {:?} is unsuffixed", lit); if !lit.kind.is_unsuffixed() { - self.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span }); + self.dcx().emit_err(errors::SuffixedLiteralInAttribute { span: lit.span }); } Ok(lit) @@ -356,10 +353,11 @@ impl<'a> Parser<'a> { Ok(nmis) } - /// Matches the following grammar (per RFC 1559). + /// Parse a meta item per RFC 1559. + /// /// ```ebnf - /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; - /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; + /// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ; + /// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ; /// ``` pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { // We can't use `maybe_whole` here because it would bump in the `None` @@ -387,7 +385,6 @@ impl<'a> Parser<'a> { Ok(if self.eat(&token::Eq) { ast::MetaItemKind::NameValue(self.parse_unsuffixed_meta_item_lit()?) } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { - // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`. let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?; ast::MetaItemKind::List(list) } else { @@ -395,38 +392,45 @@ impl<'a> Parser<'a> { }) } - /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`. + /// Parse an inner meta item per RFC 1559. + /// + /// ```ebnf + /// MetaItemInner = UNSUFFIXED_LIT | MetaItem ; + /// ``` fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { match self.parse_unsuffixed_meta_item_lit() { Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)), - Err(err) => err.cancel(), + Err(err) => err.cancel(), // we provide a better error below } match self.parse_meta_item() { Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)), - Err(err) => err.cancel(), + Err(err) => err.cancel(), // we provide a better error below } - let token = self.token.clone(); + let mut err = errors::InvalidMetaItem { + span: self.token.span, + token: self.token.clone(), + quote_ident_sugg: None, + }; - // Check for unquoted idents in meta items, e.g.: #[cfg(key = foo)] - // `from_expansion()` ensures we don't suggest for cases such as - // `#[cfg(feature = $expr)]` in macros - if self.prev_token == token::Eq && !self.token.span.from_expansion() { + // Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and + // don't `uninterpolate` the token to avoid suggesting anything butchered or questionable + // when macro metavariables are involved. + if self.prev_token == token::Eq + && let token::Ident(..) = self.token.kind + { let before = self.token.span.shrink_to_lo(); - while matches!(self.token.kind, token::Ident(..)) { + while let token::Ident(..) = self.token.kind { self.bump(); } - let after = self.prev_token.span.shrink_to_hi(); - let sugg = InvalidMetaItemSuggQuoteIdent { before, after }; - return Err(self.dcx().create_err(InvalidMetaItemUnquotedIdent { - span: token.span, - token, - sugg, - })); + err.quote_ident_sugg = Some(errors::InvalidMetaItemQuoteIdentSugg { + before, + after: self.prev_token.span.shrink_to_hi(), + }); } - Err(self.dcx().create_err(InvalidMetaItem { span: token.span, token })) + Err(self.dcx().create_err(err)) } } diff --git a/tests/ui/attributes/nonterminal-expansion.rs b/tests/ui/attributes/nonterminal-expansion.rs index 6db7aea07458e..1b2e92a31703c 100644 --- a/tests/ui/attributes/nonterminal-expansion.rs +++ b/tests/ui/attributes/nonterminal-expansion.rs @@ -5,7 +5,7 @@ macro_rules! pass_nonterminal { ($n:expr) => { #[repr(align($n))] - //~^ ERROR expected unsuffixed literal or identifier, found `n!()` + //~^ ERROR expected unsuffixed literal, found `n!()` struct S; }; } diff --git a/tests/ui/attributes/nonterminal-expansion.stderr b/tests/ui/attributes/nonterminal-expansion.stderr index 78541495b3284..b640575d17dc7 100644 --- a/tests/ui/attributes/nonterminal-expansion.stderr +++ b/tests/ui/attributes/nonterminal-expansion.stderr @@ -1,4 +1,4 @@ -error: expected unsuffixed literal or identifier, found `n!()` +error: expected unsuffixed literal, found `n!()` --> $DIR/nonterminal-expansion.rs:7:22 | LL | #[repr(align($n))] diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs index 408eaffccf7d9..d885281249203 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -28,8 +28,8 @@ struct S9; macro_rules! generate_s10 { ($expr: expr) => { #[cfg(feature = $expr)] - //~^ ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")` - //~| ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")` + //~^ ERROR expected unsuffixed literal, found `concat!("nonexistent")` + //~| ERROR expected unsuffixed literal, found `concat!("nonexistent")` struct S10; } } diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index 12557ff636041..3dd0823389cde 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -54,7 +54,7 @@ LL | #[cfg(a = b"hi")] | | | help: consider removing the prefix -error: expected unsuffixed literal or identifier, found `concat!("nonexistent")` +error: expected unsuffixed literal, found `concat!("nonexistent")` --> $DIR/cfg-attr-syntax-validation.rs:30:25 | LL | #[cfg(feature = $expr)] @@ -65,7 +65,7 @@ LL | generate_s10!(concat!("nonexistent")); | = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected unsuffixed literal or identifier, found `concat!("nonexistent")` +error: expected unsuffixed literal, found `concat!("nonexistent")` --> $DIR/cfg-attr-syntax-validation.rs:30:25 | LL | #[cfg(feature = $expr)] diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr index 078c766deedd2..a030da5068c2d 100644 --- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr +++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr @@ -4,7 +4,7 @@ error: expected unsuffixed literal, found `test` LL | #[deprecated(note = test)] | ^^^^ | -help: surround the identifier with quotation marks to parse it as a string +help: surround the identifier with quotation marks to make it into a string literal | LL | #[deprecated(note = "test")] | + + diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.rs b/tests/ui/parser/attribute/attr-bad-meta-4.rs index cedbd1d6686bc..2a69ae5ac0639 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.rs +++ b/tests/ui/parser/attribute/attr-bad-meta-4.rs @@ -1,12 +1,17 @@ macro_rules! mac { ($attr_item: meta) => { #[cfg($attr_item)] - //~^ ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)` - //~| ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)` + //~^ ERROR expected unsuffixed literal, found `an(arbitrary token stream)` + //~| ERROR expected unsuffixed literal, found `an(arbitrary token stream)` struct S; } } mac!(an(arbitrary token stream)); +#[cfg(feature = -1)] +//~^ ERROR expected unsuffixed literal, found `-` +//~| ERROR expected unsuffixed literal, found `-` +fn handler() {} + fn main() {} diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.stderr b/tests/ui/parser/attribute/attr-bad-meta-4.stderr index a543bcb692e60..192be28db3fb8 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.stderr +++ b/tests/ui/parser/attribute/attr-bad-meta-4.stderr @@ -1,4 +1,10 @@ -error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)` +error: expected unsuffixed literal, found `-` + --> $DIR/attr-bad-meta-4.rs:12:17 + | +LL | #[cfg(feature = -1)] + | ^ + +error: expected unsuffixed literal, found `an(arbitrary token stream)` --> $DIR/attr-bad-meta-4.rs:3:15 | LL | #[cfg($attr_item)] @@ -9,7 +15,7 @@ LL | mac!(an(arbitrary token stream)); | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)` +error: expected unsuffixed literal, found `an(arbitrary token stream)` --> $DIR/attr-bad-meta-4.rs:3:15 | LL | #[cfg($attr_item)] @@ -21,5 +27,13 @@ LL | mac!(an(arbitrary token stream)); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: expected unsuffixed literal, found `-` + --> $DIR/attr-bad-meta-4.rs:12:17 + | +LL | #[cfg(feature = -1)] + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.fixed b/tests/ui/parser/attribute/attr-unquoted-ident.fixed deleted file mode 100644 index bc861ef69fb7c..0000000000000 --- a/tests/ui/parser/attribute/attr-unquoted-ident.fixed +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -Zdeduplicate-diagnostics=yes -//@ run-rustfix - -#![allow(unexpected_cfgs)] - -fn main() { - #[cfg(key="foo")] - //~^ ERROR expected unsuffixed literal, found `foo` - //~| HELP surround the identifier with quotation marks to parse it as a string - println!(); - #[cfg(key="bar")] - println!(); - #[cfg(key="foo bar baz")] - //~^ ERROR expected unsuffixed literal, found `foo` - //~| HELP surround the identifier with quotation marks to parse it as a string - println!(); -} diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.rs b/tests/ui/parser/attribute/attr-unquoted-ident.rs index 8bdb8605ebb4f..5b15b8d69fcf8 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.rs +++ b/tests/ui/parser/attribute/attr-unquoted-ident.rs @@ -1,17 +1,25 @@ //@ compile-flags: -Zdeduplicate-diagnostics=yes -//@ run-rustfix #![allow(unexpected_cfgs)] fn main() { #[cfg(key=foo)] //~^ ERROR expected unsuffixed literal, found `foo` - //~| HELP surround the identifier with quotation marks to parse it as a string + //~| HELP surround the identifier with quotation marks to make it into a string literal println!(); #[cfg(key="bar")] println!(); #[cfg(key=foo bar baz)] //~^ ERROR expected unsuffixed literal, found `foo` - //~| HELP surround the identifier with quotation marks to parse it as a string + //~| HELP surround the identifier with quotation marks to make it into a string literal println!(); } + +// Don't suggest surrounding `$name` or `nickname` with quotes: + +macro_rules! make { + ($name:ident) => { #[doc(alias = $name)] pub struct S; } + //~^ ERROR expected unsuffixed literal, found `nickname` +} + +make!(nickname); //~ NOTE in this expansion diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.stderr b/tests/ui/parser/attribute/attr-unquoted-ident.stderr index 99484a51110f1..e0f99459c44e7 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.stderr +++ b/tests/ui/parser/attribute/attr-unquoted-ident.stderr @@ -1,24 +1,35 @@ error: expected unsuffixed literal, found `foo` - --> $DIR/attr-unquoted-ident.rs:7:15 + --> $DIR/attr-unquoted-ident.rs:6:15 | LL | #[cfg(key=foo)] | ^^^ | -help: surround the identifier with quotation marks to parse it as a string +help: surround the identifier with quotation marks to make it into a string literal | LL | #[cfg(key="foo")] | + + error: expected unsuffixed literal, found `foo` - --> $DIR/attr-unquoted-ident.rs:13:15 + --> $DIR/attr-unquoted-ident.rs:12:15 | LL | #[cfg(key=foo bar baz)] | ^^^ | -help: surround the identifier with quotation marks to parse it as a string +help: surround the identifier with quotation marks to make it into a string literal | LL | #[cfg(key="foo bar baz")] | + + -error: aborting due to 2 previous errors +error: expected unsuffixed literal, found `nickname` + --> $DIR/attr-unquoted-ident.rs:21:38 + | +LL | ($name:ident) => { #[doc(alias = $name)] pub struct S; } + | ^^^^^ +... +LL | make!(nickname); + | --------------- in this macro invocation + | + = note: this error originates in the macro `make` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors From ab1a67e5eefd942a50969dcd3ae26a2937c6700a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 6 May 2024 11:10:42 +0200 Subject: [PATCH 9/9] Migrate `run-make/rustdoc-io-error` to `rmake.rs` --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/rustdoc-io-error/Makefile | 20 ------------ tests/run-make/rustdoc-io-error/rmake.rs | 31 +++++++++++++++++++ 3 files changed, 31 insertions(+), 21 deletions(-) delete mode 100644 tests/run-make/rustdoc-io-error/Makefile create mode 100644 tests/run-make/rustdoc-io-error/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 8ebcb439382cc..892923affcc3a 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -244,7 +244,6 @@ run-make/rlib-format-packed-bundled-libs-3/Makefile run-make/rlib-format-packed-bundled-libs/Makefile run-make/rmeta-preferred/Makefile run-make/rustc-macro-dep-files/Makefile -run-make/rustdoc-io-error/Makefile run-make/rustdoc-output-path/Makefile run-make/rustdoc-scrape-examples-invalid-expr/Makefile run-make/rustdoc-scrape-examples-macros/Makefile diff --git a/tests/run-make/rustdoc-io-error/Makefile b/tests/run-make/rustdoc-io-error/Makefile deleted file mode 100644 index 27f5ecf94aba3..0000000000000 --- a/tests/run-make/rustdoc-io-error/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -include ../tools.mk - -# This test verifies that rustdoc doesn't ICE when it encounters an IO error -# while generating files. Ideally this would be a rustdoc-ui test, so we could -# verify the error message as well. - -# ignore-windows -# The test uses `chmod`. - -OUTPUT_DIR := "$(TMPDIR)/rustdoc-io-error" - -# This test operates by creating a temporary directory and modifying its -# permissions so that it is not writable. We have to take special care to set -# the permissions back to normal so that it's able to be deleted later. -all: - mkdir -p $(OUTPUT_DIR) - chmod u-w $(OUTPUT_DIR) - -$(shell $(RUSTDOC) -o $(OUTPUT_DIR) foo.rs) - chmod u+w $(OUTPUT_DIR) - exit $($(.SHELLSTATUS) -eq 1) diff --git a/tests/run-make/rustdoc-io-error/rmake.rs b/tests/run-make/rustdoc-io-error/rmake.rs new file mode 100644 index 0000000000000..632d75cba53c1 --- /dev/null +++ b/tests/run-make/rustdoc-io-error/rmake.rs @@ -0,0 +1,31 @@ +// This test verifies that rustdoc doesn't ICE when it encounters an IO error +// while generating files. Ideally this would be a rustdoc-ui test, so we could +// verify the error message as well. +// +// It operates by creating a temporary directory and modifying its +// permissions so that it is not writable. We have to take special care to set +// the permissions back to normal so that it's able to be deleted later. + +use run_make_support::{rustdoc, tmp_dir}; +use std::fs; + +fn main() { + let out_dir = tmp_dir().join("rustdoc-io-error"); + let output = fs::create_dir(&out_dir).unwrap(); + let mut permissions = fs::metadata(&out_dir).unwrap().permissions(); + permissions.set_readonly(true); + fs::set_permissions(&out_dir, permissions.clone()).unwrap(); + + let output = rustdoc().input("foo.rs").output(&out_dir).command_output(); + + // Changing back permissions. + permissions.set_readonly(false); + fs::set_permissions(&out_dir, permissions).unwrap(); + + // Checks that rustdoc failed with the error code 1. + assert_eq!(output.status.code().unwrap(), 1); + assert!(!output.status.success()); + let stderr = String::from_utf8(output.stderr).unwrap(); + + assert!(stderr.contains("error: couldn't generate documentation: Permission denied")); +}